網店版重生系列:都是Spring配置中自動注入惹的禍

在對Spring Container管理的bean進行配置時,有一個很好用的功能就是自動注入,可以根據不同規則對bean所依賴的bean進行自動set,相信最常用的就是設置default-autowire="byName"這種方式啦;這樣我們在進行配置時就可以減少很多的xml代碼、當我們在Java代碼中新增或減少bean的注入時就無需再對xml配置進行同步變更(針對採取xml配置的方式,若採用Annotation的方式則不存在該問題),從而提高了編碼效率;

一般情況下采取這種自動注入的方式MS也沒啥問題,但是在一些特殊情況下可能會導致莫名其妙的問題,從而要花費大量的時間去排錯;在最近的一個項目中就被我遇上了;問題大概是這樣的:以前的應用基於Oracle單數據源進行開發,Spring配置採取byName自動注入;但由於數據量劇增導致Oracle服務器不堪重負,小型機擴容成本太高,於是我們決定將原有應用改造成基於Mysql的按用戶水平劃分的分佈式DB結構;這樣的話,就需要修改DAO層關於datasource相關的一些配置,在調整過程中,問題就產生了;

原有與datasource相關的大致配置如下:

所有的DAO配置中都設置parent="daoDefinition",並在Java實現中extends SqlMapClientDaoSupport;

應用改造時,我們採用了基於Spring的AbstractRoutingDataSource來實現動態數據源的加載,但由於應用中只有部分表的數據能進行分庫,所以改造後的系統中將會存在兩種類型的數據源,其一仍然爲原Oracle主庫,通過JNDI訪問、其二爲新增的Mysql分庫,通過動態ds訪問;

由於AbstractRoutingDataSource從當前線程中獲取綁定的用戶信息,而在同一次用戶的操作中,可能會存在既訪問原來的Oracle主庫、又訪問Mysql分庫的情況,所以動態ds中需要兼容這種情況,並且在每次DB操作完成之後需要清空當前線程中綁定的變量,這樣主要是爲了避免所有的DAO層都進行變動,但在哪裏自動完成當前線程綁定變量的清空操作呢?當然是在SqlMapClientTemplate中,因爲所有的DAO操作都是通過這個template封裝接口進行訪問的,所以需要繼承該類並對所有的method進行擴展;新的配置如下:

涉及到訪問Mysql分庫的DAO均設置parent="ddbDaoDefinition",並在Java實現中extends DdbSqlMapClientDaoSupport;

這樣的配置MS沒有問題,template中已經明確設置採用動態ds,DAO實現類中也已明確繼承新的template類!後來經跟蹤代碼發現:還是Spring的自動注入惹的禍
原因如下:

SqlMapClientDaoSupport中可以自動注入3個bean:datasource、sqlMapClient、sqlMapClientTemplate;而這3個bean的注入是有先後順序的,其實datasource、sqlMapClient都是設置到sqlMapClientTemplate中的!問題就出現在這裏了;
在我們的配置中,parent中顯示設置了sqlMapClientTemplate,而沒有設置其他兩個屬性;按照Spring自動注入的默認規則,首先會將顯示set的bean注入,此時的sqlMapClientTemplate是被設置了動態ds的正確的bean,但是顯示set注入完成之後,Spring還會根據是否自動注入掃描bean裏面的set方法,完成非顯示bean的注入,此時問題就出現了,Spring根據默認datasource這個name找到了原有的基於JNDI的那個bean進行注入了,於是sqlMapClientTemplate中的datasource就被覆蓋了,也即原來正確的動態ds被替換回了原有的基於JNDI的Oracle主庫的datasource!

原因找到之後問題就好解決了,方法很多,比如:

  1. 在ddbDaoDefinition配置中增加顯示設置<property name="dataSource" ref="mixedDdbDatasource"/>;
    注意:爲保險起見,這個顯示datasource的set放在sqlMapClientTemplate之後,因爲Spring會按照設置的先後順序進行注入,若放在sqlMapClientTemplate之前,則會被後者覆蓋掉,具體依賴於被注入bean內set方法的實現;
  2. 去掉DAO配置文件中的自動注入;其實DAO層一般不會依賴於其他的bean,都是被依賴的,所以這個自動注入完全沒有必要,反而給應用帶來隱患;
發佈了135 篇原創文章 · 獲贊 69 · 訪問量 97萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章