使用spring中的Log4jConfigListener有如如下好处:
   1. 动态的改变记录级别和策略,不需要重启Web应用,如《Effective Enterprise Java》所说。
   2. 把log文件定在 /WEB-INF/logs/ 而不需要写绝对路径。
因为 系统把web目录的路径压入一个叫webapp.root的系统变量。这样写log文件路径时不用写绝对路径了.

log4j.appender.logfile.File=${webapp.root}/WEB-INF/logs/myfuse.log
    3. 可以把log4j.properties和其他properties一起放在/WEB-INF/ ,而不是Class-Path。
    4.log4jRefreshInterval为60000表示 开一条watchdog线程每60秒扫描一下配置文件的变化;
    在web.xml 添加 
     <context-param>
         <param-name>log4jConfigLocation</param-name>
         <param-value>WEB-INF/log4j.properties</param-value>
     </context-param>    <context-param>
         <param-name>log4jRefreshInterval</param-name>
         <param-value>60000</param-value>
     </context-param>    <listener>
         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
     </listener>  
 
===========
<context-param>
   <param-name>log4jConfigLocation</param-name>
   <param-value>classpath:resource/properties/log4j.properties</param-value>
  </context-param><listener>
   <listener-class>
    org.springframework.web.util.Log4jConfigListener
   </listener-class>
  </listener>


在web.xml有几个条目和log4j有关,它们是: 


1. 1. 
2. <context-param> 
3.         <param-name>webAppRootKey</param-name> 
4.         <param-value>petclinic.root</param-value> 
5. </context-param> 
6. 
7. 2. 
8. <context-param> 
9.         <param-name>log4jConfigLocation</param-name> 
10.         <param-value>/WEB-INFclasseslog4j.properties</param-value> 
11. </context-param> 
12. 
13. 
14. 3.(该条目在petclinic中被注释掉了) 
15. <listener> 
16.    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> 
17. </listener>


我们知道,在web-application中使用log4j,有很多配置方式:


a.


用servlet或者ServletContextListener对log4j做配置。通常,你不需要亲自编写servlet或者 listener,比如直接利用log4j的com.apache.jakarta.log4j.Log4jInit类,Spring的 org.springframework.web.util.Log4jConfigServlet和 org.springframework.web.util.Se


rvletContextListener,这种方式配置灵活,可以通过参数条目自行指定log4j.properties的位置。



b.


把log4j 的默认配置文件(log4j.properties)放在classpath中,通常是/web-inf/classes目录下.这种方式是log4j的 默认配置方式,无须其他配置。缺点就是无法灵活的通过配置文件来指定log4j.properties的文件位置。在我们的petclinic项目中,因 为listener条目被注释,所以采用的也是这种缺省方式。




现在我们考虑listener条目没有被注释的情况,这种情况和注册Log4jConfigServlet的目的是一样的,只是必须在支持listener的servlet container中使用。



找 到.Log4jConfigServlet和ServletContextListener的源码,他们都在适当的地方 (callback method)调用了Log4jWebConfigurer.initLogging(getServletContext()); 定位到这个方法,第一句就是:WebUtils.setWebAppRootSystemProperty(servletContext);再定位到该 方法,方法很短:


1. 
2. 
3. public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException { 
4.         String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM); 
5.         String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY); 
6.         String oldValue = System.getProperty(key); 
7.         if (oldValue != null) { 
8.             throw new IllegalStateException("WARNING: Web app root system property already set: " + key + " = " + 
9.                                                                  
10. 
11. " - Choose unique webAppRootKey values in your web.xml files!"); 
12.         } 
13.         String root = servletContext.getRealPath("/"); 
14.         if (root == null) { 
15.             throw new IllegalStateException("Cannot set web app root system property when WAR file is not  
16. 
17. expanded"); 
18.         } 
19.         System.setProperty(key, root); 
20. "Set web app root system property: " + key + " = " + root); 
21.     }





从代码看出,该方法其实就是把该web application的根目录的绝对文件路径作为属性保存在 System的属性列表中。该属性的名字,由web.xml文件中的名为"webAppRootKey"的参数值指出。如果不在web.xml中定义 webAppRootKey参数,那么属性名就是缺省的"webapp.root".在我们的petclinic项目中已经定义了 webAppRootKey参数,其值为"petclinic.root",因此,属性的名字就是"petclinic.root".



再 回到Log4jWebConfigurer.initLogging(getServletContext()),接下来的行为是从web.xml中获取 log4jConfigLocation和log4jRefreshInterval.前者指出log4j配置文件(有可能是xml格式)的位置和名字, 后者则指出重新都取配置文件的时间间隔.然后调用Log4jConfigurer.initLogging()方法对log4j做配置。从 Log4jConfigurer.initLogging()方法我们可以看到,针对不同格式的配置文件(properties或者xml), Log4jConfigurer采用不同的lo4j configurator类做配置,例如DOMConfigurator或者 PropertyConfigurator。



至此,关于petclinic中关于log4j的配置,我们已经基本上弄清楚了。可是System对象中的


petclinic.root属性在什么时候使用呢?在web-inf/classes下面的log4j.properties文件中,有这么一句:


log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log


这 样,我们就用上了petclinic.root属性了。从上面的分析可知,如果你不在web.xml中定义webAppRootKey参数,那么你就得把 log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log


中的petclinic.root变量改为webapp.root变量或者干脆换成别的绝对路径了。 


在web.xml有几个条目和log4j有关,它们是:  
 
1. 1. 
2. <context-param> 
3.         <param-name>webAppRootKey</param-name> 
4.         <param-value>petclinic.root</param-value> 
5. </context-param> 
6. 
7. 2. 
8. <context-param> 
9.         <param-name>log4jConfigLocation</param-name> 
10.         <param-value>/WEB-INFclasseslog4j.properties</param-value> 
11. </context-param> 
12. 
13. 
14. 3.(该条目在petclinic中被注释掉了) 
15. <listener> 
16.    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> 
17. </listener>



我们知道,在web-application中使用log4j,有很多配置方式:


a.


用servlet或者ServletContextListener对log4j做配置。通常,你不需要亲自编写servlet或者 listener,比如直接利用log4j的com.apache.jakarta.log4j.Log4jInit类,Spring的 org.springframework.web.util.Log4jConfigServlet和 org.springframework.web.util.Se


rvletContextListener,这种方式配置灵活,可以通过参数条目自行指定log4j.properties的位置。



b.


把log4j 的默认配置文件(log4j.properties)放在classpath中,通常是/web-inf/classes目录下.这种方式是log4j的 默认配置方式,无须其他配置。缺点就是无法灵活的通过配置文件来指定log4j.properties的文件位置。在我们的petclinic项目中,因 为listener条目被注释,所以采用的也是这种缺省方式。




现在我们考虑listener条目没有被注释的情况,这种情况和注册Log4jConfigServlet的目的是一样的,只是必须在支持listener的servlet container中使用。



找 到.Log4jConfigServlet和ServletContextListener的源码,他们都在适当的地方 (callback method)调用了Log4jWebConfigurer.initLogging(getServletContext()); 定位到这个方法,第一句就是:WebUtils.setWebAppRootSystemProperty(servletContext);再定位到该 方法,方法很短:



1. 
2. 
3. public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException { 
4.         String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM); 
5.         String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY); 
6.         String oldValue = System.getProperty(key); 
7.         if (oldValue != null) { 
8.             throw new IllegalStateException("WARNING: Web app root system property already set: " + key + " = " + 
9.                                                                  
10. 
11. " - Choose unique webAppRootKey values in your web.xml files!"); 
12.         } 
13.         String root = servletContext.getRealPath("/"); 
14.         if (root == null) { 
15.             throw new IllegalStateException("Cannot set web app root system property when WAR file is not  
16. 
17. expanded"); 
18.         } 
19.         System.setProperty(key, root); 
20. "Set web app root system property: " + key + " = " + root); 
21.     }





从代码看出,该方法其实就是把该web application的根目录的绝对文件路径作为属性保存在 System的属性列表中。该属性的名字,由web.xml文件中的名为"webAppRootKey"的参数值指出。如果不在web.xml中定义 webAppRootKey参数,那么属性名就是缺省的"webapp.root".在我们的petclinic项目中已经定义了 webAppRootKey参数,其值为"petclinic.root",因此,属性的名字就是"petclinic.root".



再 回到Log4jWebConfigurer.initLogging(getServletContext()),接下来的行为是从web.xml中获取 log4jConfigLocation和log4jRefreshInterval.前者指出log4j配置文件(有可能是xml格式)的位置和名字, 后者则指出重新都取配置文件的时间间隔.然后调用Log4jConfigurer.initLogging()方法对log4j做配置。从 Log4jConfigurer.initLogging()方法我们可以看到,针对不同格式的配置文件(properties或者xml), Log4jConfigurer采用不同的lo4j configurator类做配置,例如DOMConfigurator或者 PropertyConfigurator。



至此,关于petclinic中关于log4j的配置,我们已经基本上弄清楚了。可是System对象中的


petclinic.root属性在什么时候使用呢?在web-inf/classes下面的log4j.properties文件中,有这么一句:


log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log


这 样,我们就用上了petclinic.root属性了。从上面的分析可知,如果你不在web.xml中定义webAppRootKey参数,那么你就得把 log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log


中的petclinic.root变量改为webapp.root变量或者干脆换成别的绝对路径了。