springMVC+log4j源码简单分析

之前说过使用Spring做web项目时,及时不在web.xml中定义log4j.xml的路径,在实际仍可以正确运行,下面将根据源码来简单分析一下:

1.web.xml配置如下:

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>maven</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>maven</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

 2.将log4j.xml文件放在web-inf/classes下:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- Appenders -->
	
	<appender name="files" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="File" value="${catalina.base}/logs/mytest.log"/>
		<param name="DatePattern" value="'.'yyyy-MM-dd'.log'"/>
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n"/>
		</layout>
	</appender>
	
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss SSSS\} %-5p] [%t] %c{3\} - %m%n" />
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="org.springframework.samples.mvc">
		<level value="info" />
		<appender-ref ref="files"/>
	</logger>
	
	<logger name="com.zxhz.maventest">
		<level value="info" />
		<appender-ref ref="files"/>
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" />
		<appender-ref ref="files"/>
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" />
		<appender-ref ref="files"/>
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" />
		<appender-ref ref="files"/>
	</logger>

	<logger name="org.springframework.http">
		<level value="debug" />
		<appender-ref ref="files"/>
	</logger>

	<logger name="org.springframework.web">
		<level value="debug" />
		<appender-ref ref="files"/>
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="warn" />
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

 3.开始分析过程:

 

  当启动Tomcat的时候,Tomcat会读取web.xml配置文件,根据配置文件加载数据从web.xml文件中我们可以看到Tomcat会先加载

 

<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

 这个<listener>将会被先运行。再ContextLoaderListener.java这个类里我们可以看到:

package org.springframework.web.context;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

	private ContextLoader contextLoader;


	/**
	 * Initialize the root web application context.
	 */
	public void contextInitialized(ServletContextEvent event) {
		this.contextLoader = createContextLoader();
		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}

	//......

}

 首先这里会先运行contextInitialized()对其进行初始化操作并且会调用contextLoader的initWebApplicationContext方法并且在initWebApplicationContext方法中会创建一个logger

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);//初始化log
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
//........略1000字。。。。

 当执行

Log logger = LogFactory.getLog(ContextLoader.class);

 的时候会去调用会去找到LogFactory.getLog方法最终这个方法会通过LogManager类中的静态代码块去调用到Log4j中的Loader.class中的方法完成Log4j的初始化:

static {
      /***
       *  ..........
       */
      // if the user has not specified the log4j.configuration
      // property, we search first for the file "log4j.xml" and then
      // "log4j.properties"
      if(configurationOptionStr == null) {	
	url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
	if(url == null) {
	  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
	}
      } else {
	try {
	  url = new URL(configurationOptionStr);
	} catch (MalformedURLException ex) {
	  // so, resource is not a URL:
	  // attempt to get the resource from the class path
	  url = Loader.getResource(configurationOptionStr); 
	}	
      }
      
      // If we have a non-null url, then delegate the rest of the
      // configuration to the OptionConverter.selectAndConfigure
      // method.
      if(url != null) {
	    LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
        try {
            OptionConverter.selectAndConfigure(url, configuratorClassName,
					   LogManager.getLoggerRepository());
        } catch (NoClassDefFoundError e) {
            LogLog.warn("Error during default initialization", e);
        }
      } else {
	    LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }
    } else {
        LogLog.debug("Default initialization of overridden by " + 
            DEFAULT_INIT_OVERRIDE_KEY + "property."); 
    }  
  } 

 Loader.getResource

static public URL getResource(String resource) {
    ClassLoader classLoader = null;
    URL url = null;
    
    try {
  	if(!java1 && !ignoreTCL) {
  	  classLoader = getTCL();
  	  if(classLoader != null) {
  	    LogLog.debug("Trying to find ["+resource+"] using context classloader "
  			 +classLoader+".");
  	    url = classLoader.getResource(resource);      
  	    if(url != null) {
  	      return url;
  	    }
  	  }
  	}

 这就是为什么我们不在web.xml中定义log4j.xml的配置文件同样也可以正常的使用的原因了

 

你可能感兴趣的:(springMVC)