記錄一次升級公司框架導致的service注入失敗的問題
背景:公司使用的還是jdk7,早就想升級到jdk8,但是很坑爹的是,公司的框架使用的是Netty3.2.7和spring3.x,不能升級,jdk8必須使用spring4.x才可以,當然,spring4.x可以向下相容jdk7.思考再三,長痛不如短痛,升級Netty3.2.7到Netty4.1.31(Netty最新版本是5.x但是廢棄了,不建議使用),spring3.x升級到spring4.3.20,這樣就可以升級到jdk8了
Netty4.x居然不相容Netty3.x,連包名都換了,升級到4.1.31的過程是痛苦的,程式碼各種紅,各種踩坑,這不是本篇重點,後面寫部落格一遍Netty升級的踩坑記錄
問題:升級以後,Controller注入service失敗,跟蹤發現為null,如下圖:
最初猜測是spring沒有載入到,因此寫了工具類來驗證,如下圖:
可以看到,的確是拿到了注入的service,但是為啥是null呢?
難道拿到的controller和當前controller不是同一個嘛?
居然還真不是同一個,那麼注入失敗,也就找到原因了,下面排查為啥不是同一個controller
跟蹤公司框架原始碼,發現如下程式碼:
用反射獲取的Controller,然後反射呼叫:
那麼問題就在這裡了,最初除錯的this controller是反射獲取的,當然注入失敗,無法呼叫了
嘗試解決:
(1)反射獲取的bean,如何注入spring bean物件呢?
先獲取spring中的controller,然後,修改呼叫引數,如下所示:
invokeBizMethod(course,messsage);修改為:
invokeBizMethod((BusinessCourse) ApplicationContextHelper.getBean(ClassUtil.getClassLowerName(course.getClass())), message);
除錯發現也不行,因為這個時候Controller不一定被Spring載入到,因為,Spring中載入bean的順序是不定的,當然,如果能控制Controller的載入順序先於反射呼叫的地方,也是可以解決問題的,問題轉化為(2)中的bean載入順序問題。
(2)不用反射拿物件,直接問Spring要
不能框架層反射獲取,那麼就在專案中直接獲取,因為用的是springBoot,沒有配置檔案,因此笨辦法寫一個ControllerCollect的輔助類去獲取,然後賦值
需要賦值的地方如下:
這樣可以解決問題,但是太low了
修改如下:在Controller的基類BaseController中直接獲取
然後賦值語句 更新為 httpBizEntry.setCourses(BaseController.courses);
但是這樣發現賦值為[],也就是沒有賦值成功,分析原因,是spring中bean載入順序問題。因為賦值的地方也是@Bean註解修飾的,
那麼獲取coureses的bean必須先於賦值地方的這個bean載入才可以,這樣需要解決的就是如何控制spring中bean的載入順序問題。
Spring中bean的載入順序,根據需要有明顯的載入依賴關係,首先,可以在程式碼中手動初始化載入,當然這個肯定不會用了,其次考慮用@DependOn註解來控制,但是Controller是多個,只要繼承了BaseController的都是,並且需要指定bean name,分析以後,不符合要求。最後,考慮用@Order註解來控制,修改如下:
問題解決,其實如果使用配置檔案,直接xml裡面配置,就不會出現這個問題,現在雖然解決了問題,但是也需要在程式碼裡面配置,還是不夠友好,後面還是需要考慮如何在框架層處理掉,待完善。