踩坑了?!
之前講過 當@Transactional遇到@CacheEvict,你的代碼是不是有bug! 現在要在事務提交之後清除緩存。在Spring4.2 之後,可以使用@TransactionalEventListener選擇在事務提交之後再消費對應的事件。
為了方便發送事件,偷懶使用了靜態方法:
其中,SpringUtil.getBean()方法的內部實現為:
滿心歡喜寫完代碼,一運行,直接報錯,報錯信息為 IoC 容器中不存在ApplicationEventPublisher。
怎麼解決?解決的方案也很簡單:使用@Autowired注入ApplicationEventPublisher,調用其publishEvent方法。
深入思考
可是,為什麼ApplicationEventPublisher可以通過@Autowired進行注入,卻不能使用BeanFactory#getBean方法來獲取呢?
畫外音:千萬不要只限於解決問題,多思考,知其然並知其所以然。
看過 Spring 源碼的小夥伴不知道還記不記得,在refresh()方法中,會調用prepareBeanFactory,在該方法中,註冊了可解析依賴項。
從源碼中可以知道,一些特殊實例對象是存放在DefaultListableBeanFactory#resolvableDependencies變量中的,在容器啟動時,如果發現需要注入這些特定的實例對象,就直接在該變量中獲取,自然也就不能通過BeanFactory#getBean方法來獲取了。
DEMO
寫個 demo 程序來嘗試使用一下resolvableDependencies。
測試結果和ApplicationEventPublisher一樣,可以在 Bean 中通過@Autowired的方式來注入MySpecificBean,但卻無法通過BeanFactory#getBean方法來獲取。
寫在最後
很多人都說要看源碼,但是看源碼的目的是什麼?看源碼,不是為了面試吹牛,也不是為了重複造輪子。看源碼是為了深入瞭解這個框架的底層原理,為了以後遇到問題不會懵,可以解決百度無法解決的問題。我們可以學習優秀源碼的設計思想,學習如何取一個好的類名、好的方法名,如何使用設計模式等等。
作者:程序員小黑
原文鏈接:https://juejin.im/post/5df6d6746fb9a0162c486cec
閱讀更多 追逐仰望星空 的文章