積累,創(chuàng)造,分享!

          BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
            25 Posts :: 13 Stories :: 26 Comments :: 0 Trackbacks

          問題現(xiàn)象:在做web應(yīng)用時(shí)會(huì)碰到這種情況,某些地方無法通過web當(dāng)中的ApplicationContext來獲得springIOC容器提供的bean,比如提供給外界的webservice接口,這個(gè)時(shí)候就需要手工通過ClassPathXmlApplicationContext等方式來獲取ApplicationContext,代碼如下:
          ApplicationContext context = new ClassPathXmlApplicationContext(
              "applicationContext-*.xml");
          IXXXService xxxservice = (IXXXService ) context
              .getBean("xxxservice ");
          這是一段很典型的加載。
          然而,正是這種看似到處都是的加載卻為后面的BUG埋下伏筆。
          xxxservice是具體的業(yè)務(wù)類,它向下與DAO依賴并控制著事務(wù),這里代表了一個(gè)經(jīng)典而且簡(jiǎn)單的service,具體配置略去,值得一提的是scope,這里沒有指定,默認(rèn)的是單例。
          一切都是那么順利,像這樣的service代碼寫的應(yīng)該不下幾百個(gè),可能諸位寫的更多,過程依然很陶醉,修改完畢。測(cè)試,再測(cè)試。什么?ORA-12519錯(cuò)誤!見鬼,我打造的這套號(hào)稱簡(jiǎn)易快速的SSH2框架已經(jīng)在多個(gè)項(xiàng)目好評(píng)無數(shù)久經(jīng)考驗(yàn)了,寫了不下幾百次的service居然報(bào)ORA-12519錯(cuò)誤。
          迅速打開PLSQL,檢查數(shù)據(jù)庫(kù)session,Select Count(1) From v$session t Where t.SCHEMANAME='XXX';
          隨著service的執(zhí)行,session數(shù)在增加,沒有減少的意思。是的,當(dāng)時(shí)就是這樣。

          解決思路:這種錯(cuò)誤出現(xiàn)在久經(jīng)考驗(yàn)的框架當(dāng)中,我心里是相當(dāng)不安的,居然會(huì)有這種低級(jí)趣味的錯(cuò)誤。整理思路開始分析:這段代碼唯一與以前不同的地方就是,我們?cè)趙eb應(yīng)用中,是通過容器加載提供bean的,只有容器啟動(dòng)的時(shí)候才會(huì)加載xml。那么重點(diǎn)就應(yīng)該是關(guān)注XML的加載方式了。
          在這里我們用的是ApplicationContext接口。注意看spring文檔3.5.1.2.2 在非web應(yīng)用中優(yōu)雅地關(guān)閉springioc容器。它這里用到的是AbstractApplicationContext,在取得bean后,再執(zhí)行一個(gè)context.registerShutdownHook();
          這里實(shí)驗(yàn)一把,將ApplicationContext改成AbstractApplicationContext,執(zhí)行context.close()。結(jié)果出來了,session已被正常回收,真相漸漸浮出水面。


          結(jié)論:每次加載context的做法相當(dāng)于每次都生成了一次新的spring容器,在默認(rèn)單例的情況下,如果不及時(shí)關(guān)閉context。service所依賴的DAO當(dāng)中創(chuàng)建的dataSource也一直存在(包括所有的單例情況下所生成的類),從日志看,service事務(wù)管轄中的session確實(shí)已經(jīng)關(guān)閉,但SessionFactory還是存在的。只有在容器關(guān)閉的情況下,并指定了dataSource實(shí)例配置中的destroy-method="close",dataSource單例才會(huì)被釋放。
          spring文檔當(dāng)中對(duì)生命周期也描述的很清楚。通過DisposableBean或者指定destroy-method都能很好的釋放單例對(duì)象。而prototype類型的對(duì)象需要客戶端顯式的指定釋放,釋放對(duì)象完全是客戶端控制,spring不負(fù)責(zé)釋放。
          所以,要改善context的加載方式,盡量的少多次去加載,實(shí)在沒辦法的情況下,一定要記得關(guān)閉。
          最后,寫代碼的隨意性,圖省事,不經(jīng)思考,是造成這種BUG的罪惡根源。

          posted on 2009-04-16 17:27 nighthawk 閱讀(2738) 評(píng)論(3)  編輯  收藏

          Feedback

          # re: 警惕手工加載spring配置文件導(dǎo)致數(shù)據(jù)庫(kù)session無法釋放[未登錄] 2009-04-17 11:11 gavin
          為什么每次都要加載一次配置文件?  回復(fù)  更多評(píng)論
            

          # re: 警惕手工加載spring配置文件導(dǎo)致數(shù)據(jù)庫(kù)session無法釋放 2009-04-17 16:02 空白
          集成ApplicationContextAware,獲取web環(huán)境中實(shí)例化的ApplicationContex,就可以獲取已經(jīng)實(shí)例化的bean;

          public class SpringContextUtil implements ApplicationContextAware {

          private static ApplicationContext applicationContext;

          public void setApplicationContext(ApplicationContext arg0)
          throws BeansException {
          SpringContextUtil.applicationContext = arg0;
          }

          public static ApplicationContext getApplicationContext() {
          return SpringContextUtil.applicationContext;
          }

          /**
          * <p>根據(jù)名字獲取spring容器中bean</p>
          * @param name
          * @return
          */
          public static Object getBean(String name) {
          return SpringContextUtil.getApplicationContext().getBean(name);
          }
          }  回復(fù)  更多評(píng)論
            

          # re: 警惕手工加載spring配置文件導(dǎo)致數(shù)據(jù)庫(kù)session無法釋放 2010-03-19 23:01 plusir
          在找關(guān)于registerShutdownHook是否能在web環(huán)境下起作用的文章,隨機(jī)do到了你的blog。
          文章隨便點(diǎn)了點(diǎn),沒有細(xì)看,但是只看標(biāo)題,就仿佛看到了鏡子里另外一個(gè)自己。不知道你的重構(gòu)看完了沒,我的那本擺了好幾年了,始終是擺設(shè)。core j2ee patterns一直似看不看的翻著,也不知道后ejb時(shí)代這些東西是不是有價(jià)值,不過福勒的企業(yè)應(yīng)用架構(gòu)模式到是反過來調(diào)過去的看著。
          關(guān)注著j2ee,SSH,EJB3等等等等,同時(shí)思考著設(shè)計(jì)分析框架軟件過程那些東西,經(jīng)歷何其的相似。看看你最后一篇文章的日期,想想自己那久不維護(hù)的blog,心里小小的酸楚了一下,輕輕的問候一聲,最近還好吧,我的同行 :)  回復(fù)  更多評(píng)論
            


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 梨树县| 内丘县| 珲春市| 绍兴县| 高陵县| 临江市| 新巴尔虎右旗| 丰县| 荃湾区| 兴海县| 道孚县| 永川市| 九龙县| 海门市| 岳普湖县| 南川市| 天祝| 周口市| 新疆| 临武县| 崇明县| 临邑县| 北京市| 安吉县| 霞浦县| 丁青县| 昂仁县| 红桥区| 双辽市| 永吉县| 长兴县| 黄骅市| 涟水县| 海宁市| 张家港市| 台山市| 京山县| 临安市| 台中市| 太康县| 台湾省|