踩坑了!使用 @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

寫在最後

很多人都說要看源碼,但是看源碼的目的是什麼?看源碼,不是為了面試吹牛,也不是為了重複造輪子。看源碼是為了深入了解這個框架的底層原理,為了以後遇到問題不會懵,可以解決百度無法解決的問題。我們可以學習優秀源碼的設計思想,學習如何取一個好的類名、好的方法名,如何使用設計模式等等。

最後,小黑才疏學淺,文中不足之處還望你不吝斧正,感謝你的閱讀~