前言

最近打算花点时间好好看看spring的源码,然而现在Spring的源码经过迭代的版本太多了,比较庞大,看起来比较累,所以准备从最初的版本(interface21)开始入手,仅用于学习,理解其设计思想,后续慢慢研究其每次版本变更的内容。。。

先从interface21的一个典型web工程例子看起,宠物诊所 - petclinic,因为该工程基本涵盖了Spring的APO、IOC、JDBC、Web MVC、事务、国际化、主题切换、参数校验等主要功能。。。

先从简单的走起,看下该web工程中, Log4j是如何加载的吧~~~~~~~

对应的web.xml配置

    <context-param>
<param-name>webAppRootKey</param-name>
<param-value>petclinic.root</param-value>
</context-param> <context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param> <listener>
<listener-class>com.interface21.web.util.Log4jConfigListener</listener-class>
</listener>

执行时序图(看不清的话可以点击查看原图)

时序图中的各个步骤简要分析

执行的入口在Log4jConfigListener类的contextInitialized方法,由于Log4jConfigListener类实现了ServletContextListener接口,所以在Servlet容器(tomcat)启动时,会自动调用contextInitialized方法。

步骤描述:

  1. 进入Log4jConfigListener类的contextInitialized方法,该类只有一句代码,执行Log4jWebConfigurer.initLogging方法;

        public void contextInitialized(ServletContextEvent event) {
    Log4jWebConfigurer.initLogging(event.getServletContext());
    }
  2. 进入Log4jWebConfigurer类的initLogging方法,首先,调用WebUtils.setWebAppRootSystemProperty方法,内部调用servletContext.getRealPath("/")方法获取工程实际运行的绝对路径(如:F:\004_SVN\IBP\springweb\target\spring-web-1.0-SNAPSHOT\),设置到系统变量中(System.setProperty),注意这里的key值是可以配置的,通过webAppRootKey参数配置,如在本例子的web.xml中配成了petclinic.root;
        public static void setWebAppRootSystemProperty(ServletContext servletContext) {
    String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM);
    String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY);
    String oldValue = System.getProperty(key);
    if (oldValue != null) {
    servletContext.log("WARNING: Web app root system property already set: " + key + " = " + oldValue);
    servletContext.log("WARNING: Choose unique webAppRootKey values in your web.xml files!");
    } else {
    String root = servletContext.getRealPath("/");
    System.setProperty(key, root);
    servletContext.log("Set web app root system property: " + key + " = " + root);
    }
    }
  3. 获取日志配置文件路径、刷新间隔等配置信息,日志配置文件路径可根据log4jConfigLocation参数配置,这里配置的是相对路径,通过调用ServletContext.getRealPath()获得完整路径,注意getRealPath方法的参数要以“/”开头;刷新间隔可根据log4jRefreshInterval参数配置,默认为60s;
        public static void initLogging(ServletContext servletContext) {
    // set the web app root system property
    WebUtils.setWebAppRootSystemProperty(servletContext); // only perform custom Log4J initialization in case of a config file
    String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
    if (location != null) { // interpret location as relative to the web application root directory
    if (location.charAt(0) != '/') {
    location = "/" + location;
    }
    location = servletContext.getRealPath(location); // use default refresh interval if not specified
    long refreshInterval = Log4jConfigurer.DEFAULT_REFRESH_INTERVAL;
    String intervalString = servletContext.getInitParameter(REFRESH_INTERVAL_PARAM);
    if (intervalString != null) {
    refreshInterval = Long.parseLong(intervalString);
    } // write log message to server log
    servletContext.log("Initializing Log4J from " + location); // perform actual Log4J initialization
    try {
    Log4jConfigurer.initLogging(location, refreshInterval);
    } catch (FileNotFoundException ex) {
    throw new IllegalArgumentException("Invalid log4jConfigLocation parameter: " + ex.getMessage());
    }
    }
    }
  4. 进入Log4jConfigurer类的initLogging方法,initLogging比较简单,根据配置文件后缀名,使用相应的解析器解析配置文件中的元素。
        public static void initLogging(String location, long refreshInterval) throws FileNotFoundException {
    if (!(new File(location)).exists()) {
    throw new FileNotFoundException("Log4j config file [" + location + "] not found");
    }
    if (location.toLowerCase().endsWith(XML_FILE_EXTENSION)) {
    DOMConfigurator.configureAndWatch(location, refreshInterval);
    } else {
    PropertyConfigurator.configureAndWatch(location, refreshInterval);
    }
    }

另外补充下,当Servlet容器销毁时,会调用Log4jConfigListener的contextDestroyed方法,最终是调用LogManager.shutdown,执行一些资源关闭等操作;

interface21代码参考

https://github.com/peterchenhdu/interface21

interface21 - web - Log4jConfigListener(Log4j加载流程)的更多相关文章

  1. interface21 - web - ContextLoaderListener(Spring Web Application Context加载流程)

    前言 最近打算花点时间好好看看spring的源码,然而现在Spring的源码经过迭代的版本太多了,比较庞大,看起来比较累,所以准备从最初的版本(interface21)开始入手,仅用于学习,理解其设计 ...

  2. interface21 - web - DispatcherServlet(DispatcherServlet初始化流程)

    前言 最近打算花点时间好好看看spring的源码,然而现在Spring的源码经过迭代的版本太多了,比较庞大,看起来比较累,所以准备从最初的版本(interface21)开始入手,仅用于学习,理解其设计 ...

  3. web.xml组件加载顺序

    在配置项目组件的过程中, 了解Tomcat加载组件顺序很有必要. 例如某些框架如Quartz的集群功能需要数据库的支持, 数据库的加载肯定要在框架组件加载之前. 经过查阅和Debug发现, web.x ...

  4. Cocos Creator 资源加载流程剖析【二】——Download部分

    Download流程的处理由Downloader这个pipe负责(downloader.js),Downloader提供了各种资源的"下载"方式--即如何获取文件内容,有从网络获取 ...

  5. Cocos Creator 资源加载流程剖析【一】——cc.loader与加载管线

    这系列文章会对Cocos Creator的资源加载和管理进行深入的剖析.主要包含以下内容: cc.loader与加载管线 Download部分 Load部分 额外流程(MD5 Pipe) 从编辑器到运 ...

  6. web.xml的加载过程配置详解

      一:web.xml加载过程 简单说一下,web.xml的加载过程.当我们启动一个WEB项目容器时,容器包括(JBoss,Tomcat等).首先会去读取web.xml配置文件里的配置,当这一步骤没有 ...

  7. java面试记录二:spring加载流程、springmvc请求流程、spring事务失效、synchronized和volatile、JMM和JVM模型、二分查找的实现、垃圾收集器、控制台顺序打印ABC的三种线程实现

    注:部分答案引用网络文章 简答题 1.Spring项目启动后的加载流程 (1)使用spring框架的web项目,在tomcat下,是根据web.xml来启动的.web.xml中负责配置启动spring ...

  8. Java Web应用的加载过程

    在介绍Spring IoC和MVC的加载前,用这篇小文章简单地记录下,最简单的web应用的加载过程. 一.从最简单的web应用出发 使用Eclipse直接创建一个Dynamic Web Project ...

  9. Spring Security拦截器加载流程分析--练气中期

    写在前面 上回我们讲了spring security整合spring springmvc的流程,并且知道了spring security是通过过滤器链来进行认证授权操作的.今天我们来分析一下sprin ...

随机推荐

  1. 工欲善其事,必先利其器-ecplise配置和优化

    1.eclipse下的编码设置:eclipse 中使用模板新建 JSP,xhtml等 文件时,默认的编码为:ISO-8859-1. ISO-8859-1 编码对于中文的显示是不支持的,如果要支持简体中 ...

  2. 微软Office Online服务安装部署(一)

    1.要使用office online功能,首先需要的是2台主机,并且主机的系统要求是windwos Server 我把他命名为Server和Client(两台服务器 用户必须为administrato ...

  3. crontab命令详解 含启动/重启/停止

    linux 系统则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的.另 外, 由于使用者自己也可以设置计划任务,所以, ...

  4. sendBroadcast无法接收消息可能原因

    Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-de ...

  5. git 添加分支并与远程连接

    今天由于项目需要,要改版,为了不影响当前网站,所以用分支来管理 首先,在本地添加分支dev git checkout -b dev 提交远程,让同事拉取这个分支,我是直接push了,推到远程. 同事在 ...

  6. 3R - 单词数

    lily的好朋友xiaoou333最近很空,他想了一件没有什么意义的事情,就是统计一篇文章里不同单词的总数.下面你的任务是帮助xiaoou333解决这个问题. Input 有多组数据,每组一行,每组就 ...

  7. echo 转义字符的使用

    man echo 查看 echo 的使用文档 -n 不尾随换行符 -e 启用解释反斜杠的转义功能 -E 禁用解释反斜杠的转义功能(默认) --help 显示此帮助信息并退出 --version 显示版 ...

  8. MFC禁用关闭按钮

    有时候我们在写MFC程序时,需要在对话框中开启线程处理一些事情,如果在线程执行过程中点击关闭按钮,会导致程序崩溃. 这里介绍一种解决方法,禁用关闭按钮 解决方法 开启线程前禁用关闭按钮 CMenu* ...

  9. ABP框架系列之二十七:(Feature-Management-特征管理)

    Introduction Most SaaS (multi-tenant) applications have editions (packages) those have different fea ...

  10. Unity3D连接本地或局域网MySQL数据库

    准备工作: 1.打开 Unity3D 安装目录,到这个路径下 Editor > Data > Mono > lib > mono > 2.0 拷贝出下图的五个动态链接库, ...