一、業務場景
在實現doorls7動態調用java靜態方法的過程中,java靜態方法需要依賴被容器管理的類,就像這樣:
@Component
public class RuleFunctions {
@Resource
private static RuleEntityItemInfoBiz ruleEntityItemInfoBiz;
public static double calculateCurrentMonthIncomeTax(String fileId, String salaryMonth, String taxPlanId){
//此處省略方法實現邏輯
}
}
如果直接這樣去調用calculateCurrentMonthIncomeTax方法,那么控制台一定會報java.lang.IllegalStateException: @Resource annotation is not supported on static fields異常。
注意:這里並不是spring未注入依賴,而是被static方法初始化時給清空了。
二、原理剖析
靜態變量、類變量,並不是對象的屬性,而是一個類的屬性;所以靜態方法是屬於整個類(class)的,普通方法才是屬於實體對象(也就是New出來的對象)的,spring注入是在容器中實例化對象,所以不能使用靜態方法。
而使用靜態變量、類變量擴大了靜態方法的使用范圍。在靜態方法中注入依賴在spring框架中是不推薦使用的,依賴注入的主要目的,是讓容器去產生一個對象的實例,然后在整個生命周期中使用他們,同時也讓測試工作更加容易。
一旦你使用靜態方法,就不再需要去產生這個類的實例,這會讓測試變得更加困難,同時你也不能為一個給定的類,依靠注入方式去產生多個具有不同的依賴環境的實例,這種static field是隱含共享的,並且是一種global全局狀態,spring同樣不推薦這樣去做。
三、解決方法
1、將@Autowire加到構造方法上
@Component
public class RuleFunctions {
@Resource
private static RuleEntityItemInfoBiz ruleEntityItemInfoBiz;
@Autowired
public RuleFunctions(RuleEntityItemInfoBiz ruleEntityItemInfoBiz) {
RuleFunctions.ruleEntityItemInfoBiz = ruleEntityItemInfoBiz;
}
public static double calculateCurrentMonthIncomeTax(String fileId, String salaryMonth, String taxPlanId){
//此處省略方法實現邏輯
}
}
2.使用set注入的方式
@Component
public class RuleFunctions {
@Resource
private static RuleEntityItemInfoBiz ruleEntityItemInfoBiz;
@Autowired
public void setRuleEntityItemInfoBiz(RuleEntityItemInfoBiz ruleEntityItemInfoBiz) {
RuleFunctions.ruleEntityItemInfoBiz = ruleEntityItemInfoBiz;
}
public static double calculateCurrentMonthIncomeTax(String fileId, String salaryMonth, String taxPlanId){
//此處省略方法實現邏輯
}
}
3.用@PostConstruct注解
@Component
public class RuleFunctions {
@Resource
private RuleEntityItemInfoBiz ruleEntityItemInfoBiz;
private static RuleEntityItemInfoBiz staticRuleEntityItemInfoBiz;
/**
*注釋用於在完成依賴注入以后執行任何初始化之后需要執行的方法。必須在類投入使用之前調用此方法。
*/
@PostConstruct
public void beforeInit() {
staticRuleEntityItemInfoBiz = ruleEntityItemInfoBiz;
}
public static double calculateCurrentMonthIncomeTax(String fileId, String salaryMonth, String taxPlanId){
//此處省略方法實現邏輯
}
}
四:@PostConstruct注解的說明
@PostConstruct該注解是javax.annotation包下的,被用來修飾一個非靜態的void()方法。被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,並且只會被服務器執行一次。PostConstruct在構造函數之后執行,init()方法之前執行。
@PostConstruct注釋規則:除了攔截器這個特殊情況以外,其他情況都不允許有參數,否則spring框架會報IllegalStateException;而且返回值要是void,但實際也可以有返回值,至少不會報錯,只會忽略
通常我們會是在Spring框架中使用到@PostConstruct注解 該注解的方法在整個Bean初始化中的執行順序:
Constructor(構造方法) -> @Autowired(依賴注入) -> @PostConstruct(注釋的方法)
轉載於:https://www.cnblogs.com/chenfeng1122/p/6270217.html