踩坑了!使用 @Autowired 注入成功,GetBean 方法卻獲取不到?!
- 2019 年 12 月 17 日
- 筆記
踩坑了?!
之前推文已經講過 當@Transactional遇到@CacheEvict,你的代碼是不是有bug! 現在要在事務提交之後清除緩存。在 Spring4.2 之後,可以使用@TransactionalEventListener
選擇在事務提交之後再消費對應的事件。

@TransactionalEventListener
為了方便發送事件,偷懶使用了靜態方法:

publishEven
其中,SpringUtil.getBean()
方法的內部實現為:

getBean
滿心歡喜寫完代碼,一運行,直接報錯,報錯信息為 IoC 容器中不存在ApplicationEventPublisher
。
怎麼解決?解決的方案也很簡單:使用@Autowired
注入ApplicationEventPublisher
,調用其publishEvent
方法。
深入思考
可是,為什麼ApplicationEventPublisher
可以通過@Autowired
進行注入,卻不能使用BeanFactory#getBean
方法來獲取呢?
畫外音:千萬不要只限於解決問題,多思考,知其然並知其所以然。
看過 Spring 源碼的小夥伴不知道還記不記得,在refresh()
方法中,會調用prepareBeanFactory
,在該方法中,註冊了可解析依賴項。

image.png
從源碼中可以知道,一些特殊實例對象是存放在DefaultListableBeanFactory#resolvableDependencies
變量中的,在容器啟動時,如果發現需要注入這些特定的實例對象,就直接在該變量中獲取,自然也就不能通過BeanFactory#getBean
方法來獲取了。
DEMO
寫個 demo 程序來嘗試使用一下resolvableDependencies
。

demo
測試結果和ApplicationEventPublisher
一樣,可以在 Bean 中通過@Autowired
的方式來注入MySpecificBean
,但卻無法通過BeanFactory#getBean
方法來獲取。

test
寫在最後
很多人都說要看源碼,但是看源碼的目的是什麼?看源碼,不是為了面試吹牛,也不是為了重複造輪子。看源碼是為了深入了解這個框架的底層原理,為了以後遇到問題不會懵,可以解決百度無法解決的問題。我們可以學習優秀源碼的設計思想,學習如何取一個好的類名、好的方法名,如何使用設計模式等等。
最後,小黑才疏學淺,文中不足之處還望你不吝斧正,感謝你的閱讀~