【如何在靜態方法/main方法中調用Controller】 @PostConstruct註解使用

如何在靜態方法/main方法中調用Controller

前言

根據功能需求,一般Controller層是用來處理外部請求的,最常見的就是@RequestMapping("../..")這樣的書寫,但是有時會遇到不通過外部,而由自己手動發起去調用這個控制層去發起某個操作,就是在main方法中調用調用 Controller。

靜態方法的問題

main方法在一個類中屬於一個靜態方法,所以不難想到,要在這個main方法裏使用Controller,就必須將這個Controller也聲明爲靜態的,

@SpringBootApplication
@MapperScan("com.test.mapper")
public class DemoApplication {
    @Autowired
    private static MyController myController;
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        myController.test();
    }

這樣看上去似乎沒有任何問題,我一開始也是這麼想的,但是運行之後,就會出現空指針異常!

即使加了 static ,此時自動裝配的myController仍然是空的,即使在這一步手動new一個Controller出來,但在接下來的Controller調用Service的時仍然會有Service層的空指針異常,這層讓我一度懷疑,是不是不能在main方法中調用Controller??!

空指針原因分析

我們再仔細的看看剛剛空指針異常給出的日誌

靜態字段不支持自動注入!!

@PostConstruct註解

從Java EE5規範開始,Servlet增加了兩個影響Servlet聲明週期的註解,@PostConstruct和@PreDestory,用來修飾一個非靜態的void方法。先看一下這個註解在一個類中與構造器和@Autowired的執行順序:

Constructor > @Autowired > @PosConstruct

下面這一段是根據源碼裏的註釋的,翻譯軟件翻譯而來 多少少少能消化一點

 PostConstruct註解用於需要執行的方法完成依賴注入後執行任何初始化。這個方法必須在類投入使用之前調用。這個支持依賴項的所有類都必須支持註解注入。用PostConstruct註解的方法必須調用 如果類沒有要求注入任何資源。只有一個方法可以使用此註解。

應用PostConstruct註釋必須滿足以下所有要求標準:
1.該方法不得有任何參數,除非是攔截器,在這種情況下,它採用InvocationContext對象由攔截器規範定義。
2.在攔截器類上定義的方法必須有一個
 void< METHOD>(InvocationContext)
 Object< METHOD>(InvocationContext)拋出異常
3.注意:PostConstruct攔截器方法不能拋出應用程序異常,但可能會聲明拋出已檢查的異常,包括 java.lang.Exception,如果相同的攔截器方法插入生命週期事件之外的業務或超時方法。如果一個PostConstruct攔截器方法返回一個值,它被忽略容器。
4.在非攔截器類上定義的方法必須具有簽名後: void< METHOD>()
5.應用PostConstruct的方法可以是公共的,受保護的,包私人或私人。
6.除應用程序客戶端外,方法不得爲靜態。
7.方法可能是最終的。
8.如果方法拋出未經檢查的異常,則不得放入類服務,除了EJB可以處理異常的EJB的情況甚至從他們那裏恢復過來。

被@PostConstruct註解的方法,會在依賴自動注入後執行! 

解決方案

有了上面的一些知識跟錯誤原因後,既然靜態字段不支持自動裝配,那麼如何解決呢?理一下思路:想在靜態的main方法裏使用,肯定controller也要被static修飾爲靜態的,而此時又需要controller自動裝配,那就聲明兩個controller,一個靜態的供調用,一個普通的自動裝配並將這個賦給靜態的controller! 回想一下上面提到的,@PostConstruct修飾的方法會在自動裝配後調用。

代碼

    @Autowired
    private MyController myController2; //自動裝配的controller
    private static MyController myController ; //供靜態main方法調用的controller
    @PostConstruct
    public void init() {
        myController= myController2; //完成賦予操作
    }

此時,在main方法裏對myController就能正常使用了,後續Controller調用Service層也是正常的,如果想在main函數中直接調用Service層也是差不多的做法。

結語

僅僅是一個小問題,看起來也就多加了5行的代碼,但去發掘這個原因,理解這個原因,看明白這個解決方案花了我整整一早上的時間,但這都是小事!最可怕的是,知道哪裏報錯,卻不知道錯在哪!因爲根本知道搜索什麼,方向不知道,或許是搜“SpringBoot如何手動控制發起某個Controller”,“main方法如何調用Controller”,“main方法調用Controller空指針異常”,“自動裝配報了空指針”······等等一系列問題,然而現實告訴我這些都搜不到解決方案,!所以遇到問題,正確的搜索姿勢才能解決。

仔細分析一下在這次調用自動裝配有以往使用什麼不同就能找到搜索姿勢了,首先是在一個靜態main方法裏,其次就是這個自動裝配的字段使用了static靜態修飾。

 附一下在靜態方法中調用service代碼的鏈接 https://blog.csdn.net/qq_20552525/article/details/88863430

【本文屬個人理解與看法,如有錯誤或不同看法,煩請指教】 2019-08-08 TheJam

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章