熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Spring 與 Log4J 進行動態日志配置切換

2013-11-23 20:16:47  來源: Java開源技術 

  引言
    在開發與生產環境中我們有時候需要對日志的配置進行動態切換要調試監控和檢查系統的運行時信息
   
   一般有兩種方法
    通過 Spring 的 LogjConfigListener 在啟動時開啟定時器進行定時加載配置文件
    通過 JMX 動態控制
    以上可以從我的《利用Spring來管理控制自己的應用程序》專題演講資料中獲取到更加詳細的信息包括示例的源程序地址為
   

  先說一下上面兩種方法的不同與缺點
    通過 Spring 的 LogjConfigListener則必須在後台打開線程現定時掃描然後來定時工作有點浪費
    通過 JMX 動態控制的則必須供一個管理的端口不僅有可能端口被占用(當然有個 workaround 來解決它)還有存在防火牆等等需要配置這個管理端口進行對外暴露等等

  雖然上述兩種方法存在著一些不足但是這兩種方法在特定的場合下都可以很好地來利用它進行完美地工作
    現在利用它進行封裝與擴展我們可以巧妙地進行定制並通過 Web Console 界面來更方便地進行動態切換配置信息而且不需要重新啟動正在運行中的應用程序

  分析
    通過分析 LogjConfigListener完整的類名為 orgspringframeworkwebutilLogjConfigListener 可以得到動態加載的過程與原理
    LogjConfigListenerjava

  public class LogjConfigListener implements ServletContextListener {

  public void contextInitialized(ServletContextEvent event) {
      LogjWebConfigurerinitLogging(eventgetServletContext());
     }

  public void contextDestroyed(ServletContextEvent event) {
      LogjWebConfigurershutdownLogging(eventgetServletContext());
     }
    }

  進而可以得知一切都是由 LogjWebConfigurer 來進行操作了再分析其中的代碼可以得到 LogjWebConfigurer 的工作過程並由此進行到 LogjConfigurer 中
    最後我們可以得到最直接有用的三個方法分別如下
    LogjConfigurerinitLogging(location);
    根據給定的配置文件進行初始化日志配置

  LogjConfigurerinitLogging(location refreshInterval);
    根據給定的配置文件和間隔時間進行初始化日志配置並定時重新加載配置文件

  LogjConfigurershutdownLogging();
    關閉日志

  根據以上分析接下來就是需要進行重新封裝的工作了我們同時保留原來的定時加載的功能但通過開關進行設置同時對整個功能進行封裝與擴展

  封裝與擴展
    設計一個名為 LogJRefreshInterval 的 JavaBean
    定義如下可配置選項
     private String CLASSPATH = classpath:;
     private String location = CLASSPATH + logjxml;
     private String locationRunning = location;
     private long refreshInterval = ;
     private long refreshSecond = ;
     private long refreshMinute = ;
     private long refreshHour = ;
     private boolean refreshDaemon = false;

  增加 refreshDaemon 開關在配置裡根據需要要打開是否定時進行加載日志的配置文件
    增加一系列的時間配置參數毫秒然後對這些時間進行加和總和為定時的時間
    refreshHour * * + refreshMinute * * + refreshSecond * + refreshInterval;

   封裝方法如下方法進行控制
    public interface ILogJRefreshInterval
    {
     public void init(); // 根據配置信息初始化日志
     public void destroy(); // 銷毀日志
     public void refreshIntervalThread(); // 定時加載日志的配置信息
     public void refreshIntervalImmediately(); // 立即加載默認的日志配置信息
     public void refreshIntervalImmediatelyByFilePath(String logjFilePath); // 立即加載指定的日志配置文件

  public void refreshIntervalImmediately(boolean isXmlConfigString logjConfigInfo); // 立即加載指定的日志配置文件
     public String getRunningConfing() throws Exception;//獲取正在運行的日志配置信息
    }
    構建頁面
      由於將通過 Web Console 頁面進行管理控制也更加方便當然也可以通過 Web Services 等等之類的因為 POJO 所以可以根據項目的實際情況來加以選擇
    創建 l 文件代碼如下
    <html>
    <head>
    <meta httpequiv=ContentType content=text/html; charset=UTF/>
    <title>日志動態配置管理控制台</title>
    <link rel=stylesheet type=text/css/>
    </head>
    <body>
    <img src=loggerjpg alt=日志動態配置管理控制台/>
    <form action=logJRefreshdo method=post>
     <p>配置內容(兩者只取其一)</p>
     <p><input checked type=radio name=configMethod onclick=isXmlConfigdisabled=true;logjConfigInfovalue=;logjConfigInfodisabled=true;logjFilePathdisabled=false;logjFilePathfocus();/>1LogJ的文件路徑格式如下<input name=logjFilePath ondblclick=thisvalue=/var/logjproperties size=/></p>
     <ul>
     <li>classpath:logjproperties 或者 classpath:logjxml</li>
     <li>file:C:/logjproperties 或者 file:C:/logjxml</li>
     <li>C:/logjproperties 或者 C:/logjxml</li>
     </ul>
     <p><input type=radio name=configMethod onclick=logjFilePathvalue=;logjFilePathdisabled=true;isXmlConfigdisabled=false;logjConfigInfodisabled=false;logjConfigInfofocus();/>2LogJ的詳細配置信息</p>
     <p>配置方式
     <select name=isXmlConfig>
      <option value= selected>Property</option>
      <option value=>XML</option>
     </select>(請根據實際的配置內容選擇相應的類型)</p>
     <textarea name=logjConfigInfo rows= cols= ondblclick=thisvalue=>

  # defaultlayoutConversionPattern = %t [%c{}][%p]:[%L]:%m%n
    defaultlayoutConversionPattern = %d{yyyyMMdd HH:mm:ss} [%t] [%c{}][%p]:[%L]:%m%n

  </textarea>
     <input type=submit value=提 交/>  
     <input type=reset value=重 置/>
    </form>
    <br>
    <a title=查看正在運行的LogJ配置信息>查看配置信息</a>
      
    <a title=立刻重新加載通過配置文件加載的LogJ配置信息>立刻重新加載</a>
      
    <a title=立刻停止LogJ的服務所有日志關停>立刻停止日志</a>
      
    <a title=調用Servlet來測試LogJ信息是否正常>測試是否正常</a>
    </body>
    </html>
    構建 Controller
      在此示例中直接采用簡單易用的 Spring MVC 進行控制
      直接 implements Controller 來創建三個 Controller 分別如下
     LogJRefreshController  重新加載日志配置文件的控制器
     LogJShutdownController 關閉日志的控制器
     LogJRunningController  獲取正在運行的日志配置信息的控制器
    構建一個 Servlet
     用來測試日志配置信息是否成功加載

  public class HelloServlet extends HttpServlet
    {
     private static final long serialVersionUID = L;
     private static final Logger logger = LoggergetLogger(HelloServletclass);

  public void doGet(HttpServletRequest requestHttpServletResponse response)
     {
      try
      {
       ServletOutputStream out = responsegetOutputStream();
      outprintln(<html xmlns=\\>);
       outprintln(<head>);
       outprintln(<meta httpequiv=\ContentType\ content=\text/html; charset=GBK\/>);
       outprintln(<title>動態配置測試頁面</title>);
       outprintln(<link href=\facadecss\ rel=\stylesheet\ type=\text/css\/>);
       outprintln(</head><body>);
       outprintln(<img src=\loggerjpg\ alt=\日志動態配置管理控制台\/>);
       outprintln(<p>Begin: + new Date() + <br/>);
       if(loggerisDebugEnabled())
       {
        loggerdebug(DEBUG級別的信息debugging<p>);
        outprintln(DEBUG級別的信息debugging</p>);
           }
       if(loggerisInfoEnabled())
       {
        (INFO級別的信息information<p>);
        outprintln(INFO級別的信息information</p>);
           }
       loggerwarn(warning);
       loggererror(error);
       loggerfatal(fatal);
       outprintln(End: + new Date() + <br/>);
       outprintln(<p><a href=\JavaScript:historygo()\>返  回</a>);
       outprintln(</p></body></html>);
       outflush();
      }
      catch(IOException e)
      {
       eprintStackTrace();
      }
     }
    }


    構建兩個 JSP 頁面
     一個成功的頁面 RefreshSuccessjsp代碼如下
    <%@page contentType=text/html; charset=UTF pageEncoding=UTF%>
    <html xmlns=>
    <head>
    <meta httpequiv=ContentType content=text/html; charset=UTF/>
    <title>動態配置操作成功</title>
    <link rel=stylesheet type=text/css/>
    </head>

  <body>
    <img src=loggerjpg alt=日志動態配置管理控制台/>
    <p>
    恭喜動態配置操作成功!
    <p>
    當前的配置為
    <textarea rows= cols= ReadOnly><%=requestgetAttribute(RunningConfig)%></textarea>
    <p>
    <a JavaScript:historygo()>返  回</a>
    </body>
    </html>

  以及一個失敗的頁面 RefreshFailedjsp 代碼略

   配置 Spring 的 Bean 文件(Service)
    beanRefLogJxml

  <?xml version= encoding=UTF?>
    <!DOCTYPE beans PUBLIC //SPRING//DTD BEAN//EN beansdtd>
    <beans>
     <bean id=propertyConfigurer class=orgspringframewonfigPropertyPlaceholderConfigurer>
      <property name=locations>
       <list>
        <value>classpath:LoggerConsoleproperties</value>
       </list>
      </property>
     </bean>
     <bean id=logJRefreshInterval class=netagilespringtimeloggerutilLogJRefreshInterval initmethod=init destroymethod=destroy>
      <property name=location value=${loggerlogjlocation}/>
      <property name=refreshDaemon value=${loggerlogjrefreshDaemon}/>
      <property name=refreshInterval value=${loggerlogjrefreshInterval}/>
      <property name=refreshSecond value=${loggerlogjrefreshSecond}/>  <property name=refreshMinute value=${loggerlogjrefreshMinute}/>  <property name=refreshHour value=${loggerlogjrefreshHour}/> </bean>
    </beans>

   配置 Spring 的 Bean 文件(MVC)
    beanRefMVCxml

  <?xml version= encoding=utf?>
    <!DOCTYPE beans PUBLIC //SPRING//DTD BEAN//EN beansdtd>
    <beans>
      <bean id=urlMapping class=orgspringframeworkwebservlethandlerSimpleUrlHandlerMapping>
      <property name=mappings>
       <props>
        <prop key=/logJRefreshdo>logJRefreshController</prop>
        <prop key=/logJShutdowndo>logJShutdownController</prop>
        <prop key=/logJRunningdo>logJRunningController</prop>
       </props>
      </property>
     </bean>
     <bean id=viewResolver class=orgspringframeworkwebservletviewInternalResourceViewResolver>
      <property name=prefix>
       <value>/WEBINF/jsp/</value>
      </property>
      <property name=suffix>
       <value>jsp</value>
      </property>
     </bean>
     <bean id=logJRefreshController class=netagilespringtimeloggerwebLogJRefreshController>
      <property name=successView value=RefreshSuccess/>
      <property name=failedView value=RefreshFailed/>
      <property name=logJRefreshInterval ref=logJRefreshInterval/>
     </bean>
      <bean id=logJShutdownController class=netagilespringtimeloggerwebLogJShutdownController>
      <property name=successView value=RefreshSuccess/>
      <property name=failedView value=RefreshFailed/>
      <property name=logJRefreshInterval ref=logJRefreshInterval/>
     </bean>
      <bean id=logJRunningController class=netagilespringtimeloggerwebLogJRunningController>
      <property name=successView value=RefreshSuccess/>
      <property name=failedView value=RefreshFailed/>
      <property name=logJRefreshInterval ref=logJRefreshInterval/>
     </bean>
    </beans>

   在你現有的應用中引入這兩個 Spring 的配置文件或者根據你的項目結構進行調整即可

  <?xml version= encoding=utf?>
    <!DOCTYPE beans PUBLIC //SPRING//DTD BEAN//EN beansdtd>
    <beans>
     <import resource=beanRefLogJxml />
     <import resource=beanRefMVCxml />
    </beans>

   配置 webxml 文件
      在 webxml 中增加 Spring MVC 的配置以及測試用的 Servlet 的配置完整的配置如下
    <!DOCTYPE webapp PUBLIC //Sun Microsystems Inc//DTD Web Application //EN app__dtd>
    <webapp>
     <displayname>Spring LogJ Refresh Web Application</displayname>
     <description>Spring LogJ Refresh Web Application</description>
      <contextparam>
      <paramname>contextConfigLocation</paramname>
      <paramvalue>/WEBINF/classes/beanRefApplicationxml</paramvalue>
     </contextparam>
        <listener>
            <listenerclass>orgsprntextContextLoaderListener</listenerclass>
        </listener>
      <servlet>
      <servletname>dispatcherServlet</servletname>
      <servletclass>orgspringframeworkwebservletDispatcherServlet</servletclass>
      <loadonstartup></loadonstartup>
     </servlet>
        <servlet>
      <servletname>HelloServlet</servletname>
      <displayname>HelloServlet</displayname>
      <servletclass>netagilespringtimeloggerwebHelloServlet</servletclass>
     </servlet>
         <servletmapping>
      <servletname>HelloServlet</servletname>
      <urlpattern>/HelloServlet</urlpattern>
     </servletmapping>
     <servletmapping>
      <servletname>dispatcherServlet</servletname>
      <urlpattern>*do</urlpattern>
     </servletmapping>
    </webapp>
    這樣你的項目就具有了動態日志配置切換的功能了

  校驗日志是否成功改變
    啟動應用訪問//localhost:/LogJ_Spring_Web/  如下圖所示
 

  

      可以選擇LogJ的文件路徑或者直接輸入詳細的配置文件的LogJ的詳細配置信息方式進行動態切換

      查看配置信息可以查看到當前正在運行的配置信息如下圖

   

  立刻重新加載

  可以立即加載默認的日志配置

  文件並返回默認的配置內容如下圖

  

  


    立刻停止日志

  可以立即停止日志並顯示停止前的日志配置信息如下圖

  

  測試是否正常

  可通過此測試用的 Servlet 來查看日志是否成功在重新加載新的配置文件後建議都調用一下來測試是否切換成功如下圖

  先提交 INFO 等級的配置

  然後查看測試的結果信息如下

  

  只顯示 INFO 級別的信息

  更改為 DEBUG級別並提交如下

  

  然後查看測試的結果信息如下

  

  

  顯示出 DEBUG 級別的信息出來了表明已經成功地進行動態切換

  總結

  一個簡單的封裝與擴展實現了對日志的配置進行動態切換調試監控和檢查系統的運行時信息方便了許多提升了開發效率


From:http://tw.wingwit.com/Article/program/Java/ky/201311/28220.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.