ListableBeanFactory#getBeanNamesForType(Class<?>)
這個方法的邏輯在對 FactoryBean 進行判斷時,會使用 FactoryBean 的生成的物件的型別進行判斷
- BD 的屬性資料 AttributeAccessor.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE)
- 反射建立物件並呼叫 FactoryBean#getObjectType
- 例項化 Bean 並呼叫 FactoryBean#getObjectType
那麼對於 MyBatis 這種,直接例項化 MapperFactoryBean 的 getObjectType 是不會返回確定的型別的,只有1和3會返回,如果在建立 BeanDefinition
時沒有 setAttribute,那麼就會發生提前例項化的問題
問題又在與這個提前例項化失敗時 Spring 不會丟擲異常停止應用的啟動,而是將底層的異常捕獲並列印 debug 日誌
切實遇到的問題
公司在 MyBatis-Spring 的基礎上自己進行了 SpringBoot 風格的適配,但是在建立 BeanDefinition 時沒有 setAttribute,導致如果
XML的Mapper啊這些寫得有問題,那麼 MapperFactoryBean 在例項化時會依賴相關的 MyBatis 的 Bean 的構建,當構建失敗,不會停止應用。
於是產生的問題是
- Dao/Mapper 都生成了對應的 MapperFactoryBean
- getBeanNamesForType 在沒有找到時會遍歷它們判斷
- 例項化對應的 MapperFactoryBean -> 掃描 XML 檔案 -> 解析報錯 -> 抑制異常
- 重複 3 直到處理完畢
於是就造成了一旦 XML 寫錯,控制檯就會列印大量日誌,給人感覺像是一直死迴圈處理一樣的
解決方案
實際上 Spring 和 MyBatis 在後續版本已經解決了這個這個問題,就是 setAttribute,但是公司的版本沒有繼續迭代