用Spring与Log4J进行动态日志配置切换

 

原文地址:http://www.java2000.net/viewthread.jsp?tid=6120

http://yulimin.javaeye.com/blog/200620

   利用 Spring 与 Log4J 巧妙地进行动态日志配置切换并立即生效
     引言:
    在开发与生产环境中,我们有时候需要对日志的配置进行动态切换,要调试、监控和检查系统的运行时信息。
    一般有两种方法
    1、通过 Spring 的 Log4j ConfigListener 在启动时开启定时器进行定时加载配置文件
    2、通过 JMX 动态控制
    以上可以从我的《利用Spring来管理控制自己的应用程序》专题演讲资料中获取到更加详细的信息,包括示例的源程序,地址为
     http://yulimin.javaeye.com/blog/52354
    先说一下上面两种方法的不同与缺点:
    1、通过 Spring 的 Log4j ConfigListener,则必须在后台打开线程,现定时扫描,然后来定时工作,有点浪费;
    2、通过 JMX 动态控制的则必须供一个管理的端口,不仅有可能端口被占用(当然有个 workaround 来解决它),还有存在 防火墙等等需要配置这个管理端口进行对外暴露等等。
    虽然上述两种方法存在着一些不足,但是这两种方法在特定的场合下,都可以很好地来利用它进行完美地工作。
    现在,利用它进行封装与扩展,我们可以巧妙地进行定制,并通过 Web Console 界面来更方便地进行动态切换配置信息,而且不需要重新启动正在运行中的应用程序。
     二、分析
    通过分析 Log4jConfigListener,完整的类名为 org.springwork.web.util.Log4jConfigListener ,可以得到动态加载的过程与原理。
    Log4jConfigListener.java

  1. public class Log4jConfigListener implements ServletContextListener {   
  2.     public void contextInitialized(ServletContextEvent event) {   
  3.        Log4jWebConfigurer.initLogging(event.getServletContext());   
  4.     }   
  5.     public void contextDestroyed(ServletContextEvent event) {   
  6.        Log4jWebConfigurer.shutdownLogging(event.getServletContext());   
  7.     }   
  8. }  

    进而可以得知,一切都是由 Log4jWebConfigurer 来进行操作了,再分析其中的代码,可以得到 Log4jWebConfigurer 的工作过程,并由此进行到 Log4jConfigurer 中。
    最后我们可以得到最直接有用的三个方法,分别如下:
    1、Log4jConfigurer.initLogging(location);
    根据给定的配置文件进行初始化日志配置
    2、Log4jConfigurer.initLogging(location, refreshInterval);
    根据给定的配置文件和间隔时间,进行初始化日志配置并定时重新加载配置文件,
    3、Log4jConfigurer.shutdownLogging();
    关闭日志
    根据以上分析,接下来就是需要进行重新封装的工作了,我们同时保留原来的定时加载的功能,但通过开关进行设置,同时对整个功能进行封装与扩展。

     三、封装与扩展
    1、设计一个名为 Log4JRefreshInterval 的  JavaBean
    1.1 定义如下可配置选项:


  1.  private String CLASSPATH = "classpath:";    
  2. private String location = CLASSPATH + "log4j.xml";    
  3. private String locationRunning = location;   
  4. private long refreshInterval = 60000;    
  5. private long refreshSecond = 0;     
  6. private long refreshMinute = 0;     
  7. private long refreshHour = 0;      
  8. private boolean refreshDaemon = false;  


    增加 refreshDaemon 开关,在配置里根据需要要打开是否定时进行加载日志的配置文件;
    增加一系列的时间配置参数,毫秒、秒、分、时,然后对这些时间进行加和,总和为定时的时间
    refreshHour * 3600 * 1000 + refreshMinute * 60 * 1000 + refreshSecond * 1000 + refreshInterval;
    1.2 封装方法如下方法进行控制

  1. public interface ILog4JRefreshInterval {   
  2.   public void init(); // 根据配置信息初始化日志   
  3.   
  4.   public void destroy(); // 销毁日志   
  5.   
  6.   public void refreshIntervalThread(); // 定时加载日志的配置信息   
  7.   
  8.   public void refreshIntervalImmediately(); // 立即加载默认的日志配置信息   
  9.   
  10.   public void refreshIntervalImmediatelyByFilePath(String log4jFilePath); // 立即加载指定的日志配置文件   
  11.   
  12.   public void refreshIntervalImmediately(boolean isXmlConfig, String log4jConfigInfo); // 立即加载指定的日志配置文件   
  13.   
  14.   public String getRunningConfing() throws Exception;// 获取正在运行的日志配置信息   
  15. }  


    1.3 构建页面
    由于将通过 Web Console 页面进行管理控制,也更加方便,当然也可以通过 Web Services 等等之类的,因为 POJO 所以可以根据项目的实际情况来加以选择。
    创建 index.html 文件,代码如下:

  1. <body>  
  2. <img src="logger.jpg" alt="日志动态配置管理控制台" />  
  3. <form action="log4JRefresh.do" method="post">  
  4. <p>配置内容:(两者只取其一)</p>  
  5. <p><input checked type="radio" name="configMethod"  />1、Log4J的文件路径,格式如下: <input name="log4jFilePath"  
  6.    size="100"  
  7. /></p>  
  8. <ul>  
  9.   <li>classpath:log4j.properties 或者 classpath:log4j.xml</li>  
  10.   <li>C:/log4j.properties 或者 C:/log4j.xml</li>  
  11.   <li>C:/log4j.properties 或者 C:/log4j.xml</li>  
  12. </ul>  
  13. <p><input type="radio" name="configMethod"  />2、Log4J的详细配置信息:</p>  
  14. <p>配置方式: <select name="isXmlConfig">  
  15.   <option value="0" selected>Property</option>  
  16.   <option value="1">XML</option>  
  17. </select>(请根据实际的配置内容选择相应的类型)</p>  
  18. <textarea name="log4jConfigInfo" rows="23" cols="123" >  
  19.   
  20.   
  21.   
  22. default.layout.ConversionPattern = %t [%c{3}]-[%-5p]:[%L]:%m%n   
  23.   
  24. default.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t] [%c{3}]-[%-5p]:[%L]:%m%n   
  25.   
  26.   
  27.   
  28. </textarea> <input type="submit" value="提 交" /> <input type="reset" value="重 置" /></form>  
  29. <br>  
  30. <a href="log4JRunning.do" title="查看正在运行的Log4J配置信息。">查看配置信息</a>  
  31. <a href="log4JRefresh.do" title="立刻重新加载通过配置文件加载的Log4J配置信息。">立刻重新加载</a>  
  32. <a href="log4JShutdown.do" title="立刻停止Log4J的服务,所有日志关停。">立刻停止日志</a>  
  33. <a href="HelloServlet" title="调用Servlet来测试Log4J信息是否正常。">测试是否正常</a>  
  34. </body>  
  35. </html>  


    1.4 构建 Controller
      在此示例中直接采用简单易用的 Spring MVC 进行控制。
      直接 implements Controller 来创建三个 Controller ,分别如下:
     Log4JRefreshController  重新加载日志配置文件的控制器
     Log4JShutdownController 关闭日志的控制器
     Log4JRunningController  获取正在运行的日志配置信息的控制器
    1.5 构建一个 Servlet
    用来测试日志配置信息是否成功加载

  1. public class HelloServlet extends HttpServlet {   
  2.   private static final long serialVersionUID = -4506255419343502640L;   
  3.   
  4.   private static final Logger logger = Logger.getLogger(HelloServlet.class);   
  5.   
  6.   public void doGet(HttpServletRequest request, HttpServletResponse response) {   
  7.     try {   
  8.       ServletOutputStream out = response.getOutputStream();   
  9.       out.println("<html xmlns=/"http://www.w3.org/1999/xhtml/">");   
  10.       out.println("<head>");   
  11.       out.println("< http-equiv=/"Content-Type/" content=/"text/html; charset=GBK/"/>");   
  12.       out.println("<title>动态配置测试页面</title>");   
  13.       out.println("<link href=/"facade.css/" rel=/"stylesheet/" type=/"text/css/"/>");   
  14.       out.println("</head><body>");   
  15.       out.println("<img src=/"logger.jpg/" alt=/"日志动态配置管理控制台/"/>");   
  16.       out.println("<p>Begin:" + new Date() + "<br/>");   
  17.       if (logger.isDebugEnabled()) {   
  18.         logger.debug("DEBUG级别的信息:debugging<p>");   
  19.         out.println("DEBUG级别的信息:debugging</p>");   
  20.       }   
  21.       if (logger.isInfoEnabled()) {   
  22.         logger.info("INFO级别的信息:information<p>");   
  23.         out.println("INFO级别的信息:information</p>");   
  24.       }   
  25.       logger.warn("warning");   
  26.       logger.error("error");   
  27.       logger.fatal("fatal");   
  28.       out.println("End:" + new Date() + "<br/>");   
  29.       out.println("<p><a href=/"Java:history.go(-1)/">返  回</a>");   
  30.       out.println("</p></body></html>");   
  31.       out.flush();   
  32.     } catch (IOException e) {   
  33.       e.printStackTrace();   
  34.     }   
  35.   }   
  36. }  

    1.6 构建两个 JSP 页面
    一个成功的页面 RefreshSuccess.jsp,代码如下

  1. <%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>   
  2. <html xmlns="http://www.w3.org/1999/xhtml">   
  3. <head>   
  4. < http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
  5. <title>动态配置操作成功</title>   
  6. <link href="http://www.ygblog.com/"facade.css" rel="stylesheet" type="text/css" />   
  7. </head>   
  8. <body>   
  9. <img src="http://www.ygblog.com/"logger.jpg" alt="日志动态配置管理控制台" />   
  10. <p>恭喜:动态配置操作成功!   
  11. <p>当前的配置为: <textarea rows="23" cols="123" ReadOnly><%=request.getAttribute("RunningConfig")%></textarea>   
  12. <p><a href="http://www.ygblog.com/"Java:history.go(-1)">返 回</a>   
  13. </body>   
  14. </html>  


   以及一个失败的页面 RefreshFailed.jsp ,代码略

    1.7 配置 Spring 的 Bean 文件(Service)

    beanRefLog4J.xml
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springwork.org/dtd/spring-beans.dtd">  
  3. <beans>  
  4.   <bean id="propertyConfigurer" class="org.springwork.beans.factory.config.   
  5.   
  6. PropertyPlaceholderConfigurer">  
  7.     <property name="locations">  
  8.       <list>  
  9.         <value>classpath:LoggerConsole.properties</value>  
  10.       </list>  
  11.     </property>  
  12.   </bean>  
  13.   <bean id="log4JRefreshInterval" class="net.agile.springtime.logger.util.Log4JRefreshInterval" init-method="init"  
  14.     destroy-method="destroy">  
  15.     <property name="location" value="${logger.log4j.location}" />  
  16.     <property name="refreshDaemon" value="${logger.log4j.refreshDaemon}" />  
  17.     <property name="refreshInterval" value="${logger.log4j.refreshInterval}" />  
  18.     <property name="refreshSecond" value="${logger.log4j.refreshSecond}" />  
  19.     <property name="refreshMinute" value="${logger.log4j.refreshMinute}" />  
  20.     <property name="refreshHour" value="${logger.log4j.refreshHour}" />  
  21.   </bean>  
  22. </beans>  


   1.8 配置 Spring 的 Bean 文件(MVC)

    beanRefMVC.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springwork.org/dtd/spring-beans.dtd">  
  3. <beans>  
  4.   <bean id="urlMapping" class="org.springwork.web.servlet.handler.   
  5.   
  6. SimpleUrlHandlerMapping">  
  7.     <property name="mappings">  
  8.       <props>  
  9.         <prop key="/log4JRefresh.do">log4JRefreshController</prop>  
  10.         <prop key="/log4JShutdown.do">log4JShutdownController</prop>  
  11.         <prop key="/log4JRunning.do">log4JRunningController</prop>  
  12.       </props>  
  13.     </property>  
  14.   </bean>  
  15.   <bean id="viewResolver" class="org.springwork.web.servlet.   
  16.   
  17. view.InternalResourceViewResolver">  
  18.     <property name="prefix">  
  19.       <value>/WEB-INF/jsp/</value>  
  20.     </property>  
  21.     <property name="suffix">  
  22.       <value>.jsp</value>  
  23.     </property>  
  24.   </bean>  
  25.   <bean id="log4JRefreshController" class="net.agile.springtime.logger.web.Log4JRefreshController">  
  26.     <property name="successView" value="RefreshSuccess" />  
  27.     <property name="failedView" value="RefreshFailed" />  
  28.     <property name="log4JRefreshInterval" ref="log4JRefreshInterval" />  
  29.   </bean>  
  30.   <bean id="log4JShutdownController" class="net.agile.springtime.logger.web.Log4JShutdownController">  
  31.     <property name="successView" value="RefreshSuccess" />  
  32.     <property name="failedView" value="RefreshFailed" />  
  33.     <property name="log4JRefreshInterval" ref="log4JRefreshInterval" />  
  34.   </bean>  
  35.   <bean id="log4JRunningController" class="net.agile.springtime.logger.web.Log4JRunningController">  
  36.     <property name="successView" value="RefreshSuccess" />  
  37.     <property name="failedView" value="RefreshFailed" />  
  38.     <property name="log4JRefreshInterval" ref="log4JRefreshInterval" />  
  39.   </bean>  
  40. </beans>  


  1.9 在你现有的应用中引入这两个 Spring 的配置文件,或者根据你的项目结构进行调整即可
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springwork.org/dtd/spring-beans.dtd">  
  3. <beans>  
  4.   <import resource="beanRefLog4J.xml" />  
  5.   <import resource="beanRefMVC.xml" />  
  6. </beans>  


   1.10 配置 web.xml 文件

    在 web.xml 中增加 Spring MVC 的配置以及测试用的 Servlet 的配置,完整的配置如下:
  1. <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">  
  2. <web-app>  
  3.   <display-name>Spring Log4J Refresh Web Application</display-name>  
  4.   <deion>Spring Log4J Refresh Web Application</deion>  
  5.   <context-param>  
  6.     <param-name>contextConfigLocation</param-name>  
  7.     <param-value>/WEB-INF/classes/beanRefApplication.xml</param-value>  
  8.   </context-param>  
  9.   <listener>  
  10.     <listener-class>org.springwork.web.context.ContextLoaderListener</listener-class>  
  11.   </listener>  
  12.   <servlet>  
  13.     <servlet-name>dispatcherServlet</servlet-name>  
  14.     <servlet-class>org.springwork.web.servlet.DispatcherServlet</servlet-class>  
  15.     <load-on-startup>50</load-on-startup>  
  16.   </servlet>  
  17.   <servlet>  
  18.     <servlet-name>HelloServlet</servlet-name>  
  19.     <display-name>HelloServlet</display-name>  
  20.     <servlet-class>net.agile.springtime.logger.web.HelloServlet</servlet-class>  
  21.   </servlet>  
  22.   <servlet-mapping>  
  23.     <servlet-name>HelloServlet</servlet-name>  
  24.     <url-pattern>/HelloServlet</url-pattern>  
  25.   </servlet-mapping>  
  26.   <servlet-mapping>  
  27.     <servlet-name>dispatcherServlet</servlet-name>  
  28.     <url-pattern>*.do</url-pattern>  
  29.   </servlet-mapping>  
  30. </web-app>  


这样,你的项目就具有了动态日志配置切换的功能了。

四、校验日志是否成功改变 
http://www.java2000.net/viewthread.jsp?tid=6120
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值