Spring集成log4j,日志初始化过程详解

以前研究过slf4j-log4j的使用,但具体初始化过程不是很清楚,今天闲下来,翻了一下源码,一探究竟。
日志组件介绍: http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html
Log4j包使用说明: http://www.360doc.com/content/10/1224/19/573136_81037906.shtml
Log4j配置: http://blog.csdn.net/azheng270/article/details/2173430/
Log4j初始化详解: http://donald-draper.iteye.com/blog/2332385
相关log4j的jar包,配置,使用上面链接已经说明,这里就不做介绍,今天来探究一下,与Spring的集成过程分析:
1.在web.xml配置log4属性文件位置:
      
 <context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>classpath*:log4j.properties</param-value>
	</context-param>

2.添加监听器:
<listener>
     <listener-class>
           org.springframework.web.util.Log4jConfigListener
     </listener-class>
</listener>

到这里配置完毕。
下面分析过程:
配置文件加载通过Tomcat-StandardContext
 protected synchronized void startInternal() throws LifecycleException {

        try {
            // Create context attributes that will be required
            if (ok) {
                getServletContext().setAttribute(
                        JarScanner.class.getName(), getJarScanner());
            }
            //此函数初始化Web上下文变量,log4j属性文件位置
            // Set up the context init params
            mergeParameters();

            // Call ServletContainerInitializers
            for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                initializers.entrySet()) {
                try {
                    entry.getKey().onStartup(entry.getValue(),
                            getServletContext());
                } catch (ServletException e) {
                    log.error(sm.getString("standardContext.sciFail"), e);
                    ok = false;
                    break;
                }
            }
            //添加web监听器
            // Configure and call application event listeners
            if (ok) {
                if (!listenerStart()) {
                    log.error(sm.getString("standardContext.listenerFail"));
                    ok = false;
                }
            }
}

上下文变量初始化
 private void mergeParameters() {
        Map<String,String> mergedParams = new HashMap<String,String>();
        
        String names[] = findParameters();
        for (int i = 0; i < names.length; i++) {
            mergedParams.put(names[i], findParameter(names[i]));
        }

        ApplicationParameter params[] = findApplicationParameters();
        for (int i = 0; i < params.length; i++) {
            if (params[i].getOverride()) {
                if (mergedParams.get(params[i].getName()) == null) {
                    mergedParams.put(params[i].getName(),
                            params[i].getValue());
                }
            } else {
                mergedParams.put(params[i].getName(), params[i].getValue());
            }
        }
        
        ServletContext sc = getServletContext();
        for (Map.Entry<String,String> entry : mergedParams.entrySet()) {
            //将上下文变量放在ServletContext中
            sc.setInitParameter(entry.getKey(), entry.getValue());
        }

    }

监听器添加
 public boolean listenerStart() {
        ApplicationListener listeners[] = applicationListeners;

        // Sort listeners in two arrays
        ArrayList<Object> eventListeners = new ArrayList<Object>();
        ArrayList<Object> lifecycleListeners = new ArrayList<Object>();
        for (int i = 0; i < results.length; i++) {
            if ((results[i] instanceof ServletContextAttributeListener)
                || (results[i] instanceof ServletRequestAttributeListener)
                || (results[i] instanceof ServletRequestListener)
                || (results[i] instanceof HttpSessionAttributeListener)) {
                eventListeners.add(results[i]);
            }
            if ((results[i] instanceof ServletContextListener)
                || (results[i] instanceof HttpSessionListener)) {
                lifecycleListeners.add(results[i]);
            }
        }

        // Listener instances may have been added directly to this Context by
        // ServletContextInitializers and other code via the pluggability APIs.
        // Put them these listeners after the ones defined in web.xml and/or
        // annotations then overwrite the list of instances with the new, full
        // list.
        for (Object eventListener: getApplicationEventListeners()) {
            eventListeners.add(eventListener);
        }
        setApplicationEventListeners(eventListeners.toArray());
        for (Object lifecycleListener: getApplicationLifecycleListeners()) {
            //添加监听器
            lifecycleListeners.add(lifecycleListener);
            if (lifecycleListener instanceof ServletContextListener) {
                noPluggabilityListeners.add(lifecycleListener);
            }
        }
        setApplicationLifecycleListeners(lifecycleListeners.toArray());

        // Send application start events

        if (getLogger().isDebugEnabled())
            getLogger().debug("Sending application start events");

        // Ensure context is not null
        getServletContext();
        context.setNewServletContextListenerAllowed(false);
        
        Object instances[] = getApplicationLifecycleListeners();
        if (instances == null || instances.length == 0) {
            return ok;
        }

        ServletContextEvent event = new ServletContextEvent(getServletContext());
        ServletContextEvent tldEvent = null;
        if (noPluggabilityListeners.size() > 0) {
            noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());
            tldEvent = new ServletContextEvent(noPluggabilityServletContext);
        }
        for (int i = 0; i < instances.length; i++) {
            if (instances[i] == null)
                continue;
            if (!(instances[i] instanceof ServletContextListener))
                continue;
            ServletContextListener listener =
                (ServletContextListener) instances[i];
            try {
                fireContainerEvent("beforeContextInitialized", listener);

                if (noPluggabilityListeners.contains(listener)) {
                    listener.contextInitialized(tldEvent);
                } else {
                    listener.contextInitialized(event);
                }
                fireContainerEvent("afterContextInitialized", listener);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                fireContainerEvent("afterContextInitialized", listener);
                getLogger().error
                    (sm.getString("standardContext.listenerStart",
                                  instances[i].getClass().getName()), t);
                ok = false;
            }
        }

查看Spring log4j监听器
public class Log4jConfigListener
    implements ServletContextListener
{

    public Log4jConfigListener()
    {
    }

    public void contextInitialized(ServletContextEvent event)
    {
        //初始化log4J位置,通过event.getServletContext()获取
        Log4jWebConfigurer.initLogging(event.getServletContext());
    }

    public void contextDestroyed(ServletContextEvent event)
    {
        Log4jWebConfigurer.shutdownLogging(event.getServletContext());
    }
}

log4jWeb初始化Log4jWebConfigurer
 public static void initLogging(ServletContext servletContext)
    {
        if(exposeWebAppRoot(servletContext))
            WebUtils.setWebAppRootSystemProperty(servletContext);
        String location = servletContext.getInitParameter("log4jConfigLocation");
        if(location != null)
            try
            {
                location = ServletContextPropertyUtils.resolvePlaceholders(location, servletContext);
                if(!ResourceUtils.isUrl(location))
                    location = WebUtils.getRealPath(servletContext, location);
                servletContext.log((new StringBuilder()).append("Initializing log4j from [").append(location).append("]").toString());
                String intervalString = servletContext.getInitParameter("log4jRefreshInterval");
                if(StringUtils.hasText(intervalString))
                    try
                    {
                        long refreshInterval = Long.parseLong(intervalString);
                        //初始化log4j配置
                        Log4jConfigurer.initLogging(location, refreshInterval);
                    }
                    catch(NumberFormatException ex)
                    {
                        throw new IllegalArgumentException((new StringBuilder()).append("Invalid 'log4jRefreshInterval' parameter: ").append(ex.getMessage()).toString());
                    }
                else
                    Log4jConfigurer.initLogging(location);
            }
            catch(FileNotFoundException ex)
            {
                throw new IllegalArgumentException((new StringBuilder()).append("Invalid 'log4jConfigLocation' parameter: ").append(ex.getMessage()).toString());
            }
    }


log4j属性变量配置Log4jConfigurer
public static void initLogging(String location, long refreshInterval)
        throws FileNotFoundException
    {
        String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
        File file = ResourceUtils.getFile(resolvedLocation);
        if(!file.exists())
            throw new FileNotFoundException((new StringBuilder()).append("Log4j config file [").append(resolvedLocation).append("] not found").toString());
        //xml文件
        if(resolvedLocation.toLowerCase().endsWith(".xml"))
            DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
        else
        //properties文件
            PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
    }

PropertyConfigurator,属性文件读取
public void doConfigure(Properties properties, LoggerRepository hierarchy)
    {
        repository = hierarchy;
        String value = properties.getProperty("log4j.debug");
        if(value == null)
        {
            value = properties.getProperty("log4j.configDebug");
            if(value != null)
                LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
        }
        if(value != null)
            LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
        String reset = properties.getProperty("log4j.reset");
        if(reset != null && OptionConverter.toBoolean(reset, false))
            hierarchy.resetConfiguration();
        String thresholdStr = OptionConverter.findAndSubst("log4j.threshold", properties);
        if(thresholdStr != null)
        {
            hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr, Level.ALL));
            LogLog.debug("Hierarchy threshold set to [" + hierarchy.getThreshold() + "].");
        }
        //关键是下面三个函数配置LogFactory属性
        configureRootCategory(properties, hierarchy);
        configureLoggerFactory(properties);
        parseCatsAndRenderers(properties, hierarchy);
        LogLog.debug("Finished configuring.");
        registry.clear();
    }

至此LogFactory初始化完毕。
Logger实例的获取
 public static Logger getLogger(Class clazz)
    {   
        //根据类名获取logger实例
        Logger logger = getLogger(clazz.getName());
        if(DETECT_LOGGER_NAME_MISMATCH)
        {
            Class autoComputedCallingClass = Util.getCallingClass();
            if(nonMatchingClasses(clazz, autoComputedCallingClass))
            {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", new Object[] {
                    logger.getName(), autoComputedCallingClass.getName()
                }));
                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
            }
        }
        return logger;
    }

public static Logger getLogger(String name)
    {
        //从具体的log工场实现中,获取log
        //slf4j只是提供了一个工场类接口,具体的工场实现类在相关日志Jar包中
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

写的有点匆忙,请见谅!

猜你喜欢

转载自donald-draper.iteye.com/blog/2306679
今日推荐