搜索我的静态初始化块不会执行的原因的解释,我发现类中的静态初始化器永远不会执行if it references a final。
所以我尝试通过删除MYWS_PROPS中的'final'来解决这个问题:
public class HibernateUtil {
public static String MYWS_PROPS = "/myws.properties";
private static final Logger LOG = Logger.getLogger(HibernateUtil.class.getName());
private static final SessionFactory sessionFactory = buildSessionFactory();
private static Properties sProps;
static {
try {
sProps = new Properties();
sProps.load(ServiceUtils.class.getResourceAsStream(MYWS_PROPS));
LOG.info("Loaded (from " + MYWS_PROPS + ") connection url: " + sProps.getProperty("dburl"));
}
catch (IOException e) {
LOG.severe("Cannot find properties file " + MYWS_PROPS);
}
}
private static SessionFactory buildSessionFactory() {
try {
Configuration config = new Configuration();
config = config.configure("resources/hibernate.cfg.xml");
config.setProperty("hibernate.connection.url", sProps.getProperty("dburl")); // <== NullPointerException!
SessionFactory session = config.buildSessionFactory();
return session;
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
}
但是静态阻止仍然无法执行!
保证执行静态块的正确方法是什么?
更新:下面的所有答案都提到了引用该类的要求,以便运行静态初始化。所以我再次查看我的堆栈跟踪并验证该类确实被引用(否则,为什么它会在同一个类方法中引发异常?)
Caused by: java.lang.ExceptionInInitializerError
at com.corp.dept.proj.myws.HibernateUtil.buildSessionFactory(HibernateUtil.java:76)
at com.corp.dept.proj.myws.HibernateUtil.<clinit>(HibernateUtil.java:38)
at com.corp.dept.proj.myws.ServicePortImpl.<init>(ServicePortImpl.java:82)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126)
... 70 more
Caused by: java.lang.NullPointerException
at com.corp.dept.proj.myws.HibernateUtil.buildSessionFactory(HibernateUtil.java:67)
... 77 more
但为了安全起见,我尝试了 Class.forName 建议:
Class.forName("com.corp.dept.proj.myws.HibernateUtil");
mProps.load(ServiceUtils.class.getResourceAsStream(HibernateUtil.MYWS_PROPS));
静态阻止仍无法执行。
所以我试着明确地实例化它:
HibernateUtil justExecTheDarnStaticBlock = new HibernateUtil();
mProps.load(ServiceUtils.class.getResourceAsStream(HibernateUtil.MYWS_PROPS));
但是静态阻止仍然无法执行!
我在这里缺少什么?
答案 0 :(得分:3)
在处理静态初始化时,有意义。
采用以下示例:
public class StaticTest {
private static final String someString = initSomeString();
private static final String someOtherString = initSomeOtherString();
private static final String whoops;
static {
System.out.println("static initializer");
whoops = "whoops";
}
public static void main(String[] args) {
System.out.println(someOtherString);
}
private static String initSomeString() {
System.out.println("initSomeString");
return "Initialised";
}
private static String initSomeOtherString() {
System.out.println("initSomeOtherString");
return whoops + "y daisy";
}
}
运行此类的结果如下:
initSomeString
initSomeOtherString
static initialiser
nully daisy
静态初始化按照声明的顺序发生,这意味着initSomeOtherString()
在之前被称为,初始化whoops
的静态初始化块。因此,此时whoops
仍为null
,因此生成的String
为nully daisy
而不是whoopsy daisy
。
如果我重新安排课程,以便在静态初始化之后初始化someOtherString
,我得到了我想要的内容:
public class StaticTest {
private static final String someString = initSomeString();
private static final String whoops;
static {
System.out.println("static initialiser");
whoops = "whoops";
}
private static final String someOtherString = initSomeOtherString();
public static void main(String[] args) {
System.out.println(someOtherString);
}
private static String initSomeString() {
System.out.println("initSomeString");
return "Initialised";
}
private static String initSomeOtherString() {
System.out.println("initSomeOtherString");
return whoops + "y daisy";
}
}
打印
initSomeString
static initialiser
initSomeOtherString
whoopsy daisy
这是您遇到并导致问题的行为。您通过调用sessionFactory
来初始化buildSessionFactory()
,sProps
依赖config.setProperty("hibernate.connection.url", sProps.getProperty("dburl")
^ This hasn't been initialised yet
进行初始化:
sessionFactory
解决方案? 将{{1}}的声明移至以下静态初始化程序段。
答案 1 :(得分:2)
第一次引用类时将执行静态块。 (实例化或对静态成员的引用)
答案 2 :(得分:1)
如果你创建了一个类的实例,静态块肯定会执行。
编辑:评论中找到的实际解决方案如下:
buildSessionFactory()
方法用于初始化sessionFactory
。这取决于已经调用的静态块,但事实并非如此。如果您在静态块中而不是在其声明中调用sessionFactory = buildSessionFactory();
,并且在sProps
初始化之后问题将消失。
答案 3 :(得分:1)
您链接的问题只是讨论编译时常量;引用它们不会加载该类。但是你要加载类的任何事情 - 例如Class.forName("HibernateUtil")
- 都必须运行静态初始化器。
此外,由于您正在处理的static
变量不是原始类型或String
,因此它无论如何都不能成为编译时常量。
答案 4 :(得分:0)
ClassLoader需要在静态块执行之前加载类。第一次引用类时会发生这种情况。
您可以使用Class.forName("");
强制执行此操作。有了这个,您可以使用final
变量
答案 5 :(得分:0)
如果您使用该课程,例如调用它的静态方法,创建它的实例,静态块将被执行。
另一种方法是通过调用Class.forName
来明确地加载类。当您只知道名称(作为字符串)时,这非常有用。有时您必须扫描jar文件以获取名称并使用Class.forname
加载它。