牙牙窩

          BlogJava 聯(lián)系 聚合 管理
            8 Posts :: 21 Stories :: 10 Comments :: 0 Trackbacks

          ?

          一、??????? 概述

          Spring MVC 的開發(fā)是基于 action-servlet.xml 進(jìn)行配置,但不支持開發(fā)模式下進(jìn)行動(dòng)態(tài)的配置文件載入。本文主要是介紹如何修改 Spring 的源代碼,使 Spring 支持動(dòng)態(tài)的配置文件更新,讓開發(fā)變得更加簡(jiǎn)單。

          二、??????? 實(shí)現(xiàn) action-servlet.xml 動(dòng)態(tài)載入

          ??? Spring 提取配置文件的思路 :每次 Spring MVC 會(huì)在使用前將 XML 文件載入內(nèi)存中,并生成映射類的實(shí)例,放在 Mapping Map 里。然后判斷每個(gè)請(qǐng)求,如果有其 URL 所對(duì)應(yīng)的映射,則返回其對(duì)應(yīng)的 Action 實(shí)例。

          ??? 修改思路 :將每次得到請(qǐng)求時(shí),讓程序重新載入 xml 文件,并實(shí)例化其映射,然后放入 Mapping Map 中。

          1、???????????? 首先是 FrameworkServlet ,他是 DispatcherServlet 的基類。 XML 在載入內(nèi)存后,放在一個(gè)叫 WebApplicationContext 的類中。找到 getWebApplicationContext() 方法,加入以下代碼:

          ?????? ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils

          ????????????? .instantiateClass(getContextClass());

          ?????? wac.setParent(WebApplicationContextUtils

          ????????????? .getWebApplicationContext(getServletContext()));

          ?????? wac.setServletContext(getServletContext());

          ?????? wac.setNamespace(getNamespace());

          ?????? if (getContextConfigLocation() != null ) {

          ?????????? wac

          ????????????????? .setConfigLocations(StringUtils

          ???????????????????????? .tokenizeToStringArray(

          ??????????????????????????????? getContextConfigLocation(),

          ??????????????????????????? ??? ConfigurableWebApplicationContext. CONFIG_LOCATION_DELIMITERS ));

          ?????? }

          ?????? wac.refresh();

          ?????? this . webApplicationContext = wac;

          這樣每次再讀取 WebApplicationContext 的時(shí)候,會(huì)重新載入 XML 文件一次。

          ?

          2、???????????? 修改 DispatcherServlet ,這個(gè) Servlet 是處理所有請(qǐng)求的入口。找到 getHandler() 這個(gè)方法,他負(fù)責(zé)找到相應(yīng)的 Action ,并返回其實(shí)例。將代碼中的

          ?????? Iterator it = this.handlerMappings.iterator();

          ?????? while (it.hasNext()) {

          ?????????? HandlerMapping hm = (HandlerMapping) it.next();

          ?????????? if (logger.isDebugEnabled()) {

          ????????????? logger.debug("Testing handler map [" + hm? + "] in DispatcherServlet with name '" +

          ???????????????????? getServletName() + "'");

          ?????????? }

          ?????????? handler = hm.getHandler(request);

          ?????????? if (handler != null) {

          ????????????? if (cache) {

          ????????????????? request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);

          ????????????? }

          ????????????? return handler;

          ?????????? }

          ?????? }

          改為

          ?????? initHandlerMappings();

          ??????

          ?????? Iterator it = this . handlerMappings .iterator();

          ?????? while (it.hasNext()) {

          ?????????? BeanNameUrlHandlerMapping hm = (BeanNameUrlHandlerMapping) it.next();

          ?????????? if ( logger .isDebugEnabled()) {

          ????????????? logger .debug( "Testing handler map [" + hm? + "] in DispatcherServlet with name '" +

          ???????????????????? getServletName() + "'" );

          ?????????? }

          ?????????? hm.initApplicationContext();

          ?????????? handler = hm.getHandler(request);

          ?????????? if (handler != null ) {

          ????????????? if (cache) {

          ????????????????? request.setAttribute( HANDLER_EXECUTION_CHAIN_ATTRIBUTE , handler);

          ????????????? }

          ????????????? return handler;

          ?????????? }

          ?????? }

          注解:

          1)?? 其中 BeanNameUrlHandlerMapping 是將強(qiáng)制轉(zhuǎn)換 HandlerMapping 時(shí),用子類代替父類,因?yàn)樽宇愄峁┝艘粋€(gè)重新初始化的方法 initApplicationContext() ,調(diào)用該方法可以重新載入 WebApplicationContext , 并刷新 Mapping Map

          2)?????? initHandlerMappings() DispatcherServlet 初始化 Mapping 的一個(gè)方法。在生成 WebApplicationContext 時(shí),程序還會(huì)把放在 ApplicationObjectSupport.applicationContext 保存,因此需要重新初始化一次。

          ?

          3 、修改 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping

          類中的 registerHandler() 方法,它的作用是注冊(cè) Mapping ,去掉重復(fù)性校驗(yàn),將下面幾行代碼注釋掉。

          ??? if (mappedHandler != null) {

          ??????? throw new ApplicationContextException(

          ?????????????? "Cannot map handler [" + handler + "] to URL path [" + urlPath +

          ?????????????? "]: there's already handler [" + mappedHandler + "] mapped");

          ??? }

          ?

          ?

          三、實(shí)現(xiàn) applicationContext.xml 的動(dòng)態(tài)載入

          ??? Spring 實(shí)現(xiàn)思路: applicationContext.xml Spring 默認(rèn)的配置文件,它利用配置 ContextLoaderListener 的方式,在應(yīng)用載入時(shí)啟動(dòng),并將 applicationContext.xml 載入內(nèi)存中,放在 ServletContext Attribute 中,保存的方式是一個(gè) WebApplicationContext 類。當(dāng)每次調(diào)用類時(shí), beanFactory 會(huì)調(diào)用 WebApplicationContextUtils 中的方法 getWebApplicationContext() ,得到配置信息。

          ??? 修改方法: ContextLoaderListener 初始化 WebApplicationContext 時(shí),會(huì)利用 ContextLoader 提供的方法 initWebApplicationContext() 進(jìn)行初始化,我們只需要得到 Listener 的這個(gè) ContextLoader 的實(shí)例,并重新調(diào)用一個(gè)初始化的方法就可以實(shí)現(xiàn)重新載入了。

          ??? 修改步驟:

          1 、找到 ContextLoaderListener 類的方法 contextInitialized() ,在 Context 初始化的時(shí)候?qū)?/span> ContextLoader 的引用放在 ServletContext Attribute 中:

          public void contextInitialized(ServletContextEvent event) {

          ?????? this . contextLoader = createContextLoader();

          ?????? this . contextLoader .initWebApplicationContext(event.getServletContext());

          ?????? event.getServletContext().setAttribute( "ListenerContextLoader" , this . contextLoader );

          }

          注: "ListenerContextLoader" 是自定義的名稱,可以任意修改。

          ?

          3、???????????? 找到 WebApplicationContextUtils 類的方法 getWebApplicationContext() ,修改第一行代碼:

          Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

          改為:

          ?????? Object attr = null ;

          ?????? ContextLoader cl = (ContextLoader) sc

          ????????????? .getAttribute( "ListenerContextLoader" );

          ?????? if (cl != null )

          ?????????? attr = cl.initWebApplicationContext(sc);

          這樣,在每次獲取 WebApplicationContext 時(shí),程序會(huì)重新載入 applicationContext.xml 一次。

          ?

          OK !大功告成, Enjoy your spring developing !!!

          ?

          posted on 2006-12-06 09:38 大牙 閱讀(9682) 評(píng)論(7)  編輯  收藏 所屬分類: 架構(gòu)師歷程

          Feedback

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2007-11-19 14:38 tedeyang
          good,樓主很能鉆。
          不過(guò)用監(jiān)視xml文件的方式更好一點(diǎn),否則刷新得太頻繁了。  回復(fù)  更多評(píng)論
            

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2007-11-19 14:38 tedeyang
          另外在bean依賴關(guān)系復(fù)雜的時(shí)候會(huì)比較麻煩。  回復(fù)  更多評(píng)論
            

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2008-03-27 11:25 疑問(wèn)
          我修改了怎么不成功呢?   回復(fù)  更多評(píng)論
            

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2009-07-09 11:12 hezhuo1985
          @tedeyang
          監(jiān)視xml文件是怎樣實(shí)現(xiàn)的?
            回復(fù)  更多評(píng)論
            

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2009-07-09 11:50 hezhuo1985
          實(shí)現(xiàn) applicationContext.xml 的動(dòng)態(tài)載入 ,具體怎么操作?
            回復(fù)  更多評(píng)論
            

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2011-12-08 10:48 陳華
          請(qǐng)問(wèn)樓主。如何不修改源碼實(shí)現(xiàn)這樣的需求:

          在服務(wù)器運(yùn)行的狀態(tài),修改Spring中的數(shù)據(jù)庫(kù)連接,讓它重新加載。萬(wàn)分感謝!

          QQ 705541917

          chengongmo@126.com  回復(fù)  更多評(píng)論
            

          # re: 關(guān)于Spring配置文件的動(dòng)態(tài)載入的修改 2012-02-15 15:20 jakey766
          每次進(jìn)入DispatcherServlet 時(shí)重新加載一下不太合理呀,LZ現(xiàn)在有其他方法沒(méi)?spring中的那幾個(gè)方法都用final修飾了,想改都改不了啊  回復(fù)  更多評(píng)論
            

          主站蜘蛛池模板: 资源县| 梅河口市| 会同县| 齐齐哈尔市| 铁岭县| 体育| 德兴市| 板桥市| 宝山区| 焦作市| 新化县| 湛江市| 兴业县| 石首市| 北流市| 苍溪县| 夹江县| 莆田市| 安远县| 康平县| 靖远县| 沾益县| 新野县| 广灵县| 八宿县| 清水河县| 东乡| 遂溪县| 深泽县| 平昌县| 清河县| 西平县| 伊吾县| 鸡东县| 岑溪市| 万宁市| 荔浦县| 道孚县| 临沧市| 拜城县| 石景山区|