java 靜態代碼塊和spring @value等注解注入順序
問題所在
先上代碼
java方法
@Value("${mf.cashost}")
public static String casHost;
public static String getCasHost() {
if (StringUtils.isEmpty(casHost)) {
//casHost = "http://sso.abc.com.cn/sso/";
casHost = "http://ssotest.abc.com.cn/sso/";
}
return casHost;
}
配置文件
mf.cashost=http://sso.abc.com.cn/sso/
正常我們想要的getCasHost
的值,肯定是sso.abc.com.cn
,而不是ssotest
,但是如果調用getCasHost
肯定是返回test
的,或者說,casHost最開始進到getCasHost的方法時,就是空的。
分析一波
關於實例變量與構造方法的初始化順序問題
- Java類會先執行構造方法,然后再給注解了@Value 的屬性注入值,所以在執行靜態代碼塊的時候,就會為null。
- Java 及Spring 初始化順序:java靜態屬性/靜態代碼塊(根據聲明的先后順序加載)、構造代碼塊、 構造方法(即:spring創建FetchStockSchedule的實例 交給Spring 管理)、@Value/@ AutoWired/@Resouce 等注解 的成員變量等賦值。
解決一下
解決方案
- 首先,讓當前類變成Spring的bean,
- 再使用@PostConstruct
@Value("${mf.cashost}")
private String mfCasHost;
private static String casHost;
@PostConstruct
public void init() {
casHost = mfCasHost;
}
public static String getCasHost() {
if (StringUtils.isEmpty(casHost)) {
casHost = "http://ssotest.abc.com.cn/sso/";
}
return casHost;
}
原理
Java中該注解的說明:
@PostConstruct
該注解被用來修飾一個非靜態的void()
方法。被@PostConstruct
修飾的方法會在服務器加載Servlet
的時候運行,並且只會被服務器執行一次。PostConstruct在構造函數之后執行,init()方法之前執行。
通常我們會是在Spring框架中使用到@PostConstruct注解 該注解的方法在整個Bean初始化中的執行順序:
此時的執行順序:
- 構造方法
- Before Initialization
- 使用PostConstruct注解
- InitializingBean接口
- init-method指定的初始化方法
- After Initialization