spingboot使用@Resource注入靜態變數報空指標的問題解決

Monameng發表於2020-11-25
昨天在工作中遇到這個問題,最後改為@Autowired解決,並找到了原理分析文章,記錄一下

一、業務場景

spring框架應用中有些靜態方法需要依賴被容器管理的類,就像這樣:

@Component
public class Test {
    
    @Autowired
    private static UserService userService;
    
    public static void test() {
        userService.test();
    }
}

如果直接這樣去呼叫test()方法,那麼控制檯一定會報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 Test {
    
    private static UserService userService;
    
    @Autowired
    public Test(UserService userService) {
        Test.userService = userService;
    }
    
    public static void test() {
        userService.test();
    }
}

2、用@PostConstruct註解

@Component
public class Test {
    
    private static UserService userService;
    
    @Autowired
    private UserService userService2;
    
    @PostConstruct
    public void beforeInit() {
        userService = userService2;
    }
    
    public static void test() {
        userService.test();
    }
}

四:@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

相關文章