`
seandeng888
  • 浏览: 158581 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

源码赏析之spring对log4j的锦上添花

阅读更多

Log4j在系统记录日志方面功能很强大,但是,在配置文件路径、日志文件路径及动态修改日志记录器级别等信息时却不够灵活,存在一些不足之处。好在spring提供了相关功能弥补了log4j在这方面的不足。接下来就来看一看spring是如何实现这方面功能

spring针对log4j提供了如下功能 
     1. 可以通过定期检查配置文件的变化来动态的改变记录级别和策略,不需要重启Web应用。 web.xml配置如下:

<context-param>   

      <param-name>log4jRefreshInterval</param-name>   

      <param-value>6000</param-value>   

</context-param> 
     2. 日志文件定在 web应用目录下的任何位置,而不需要写绝对路径。 
因为系统把web应用目录的路径压入一个叫webapp.root的系统变量。这样写log文件路径时不用写绝对路径了。当然也可以手动修改该系统变量。web.xml配置如下:

<context-param>

        <param-name>webAppRootKey</param-name>

        <param-value>muse.root</param-value>

</context-param>

注意:不同的应用不可以配置一样的webAppRootKey值,否则会导致系统无法正常启动。

log4j配置如下:log4j.appender.ROLLING_FILE.File=${muse.root}/WEB-INF/logs/muse.log 
   3. 可以把log4j.properties和其他properties一起放在/WEB-INF/ ,而不是Class-Path web.xml配置如下:

<context-param>

        <param-name>log4jConfigLocation</param-name>

        <param-value>/WEB-INF/log4j.xml</param-value>

</context-param>

注:如果要使webAppRootKey生效,则该项一定要配置,当然也可指定properties文件,因为如果没有配置的话,Log4jConfigListener是不会调用log4j初始化配置的。

接下来通过应用配置及源码赏析两方面来详细了解一下这些功能。

应用配置

1.1 web.xml

    所有相关的web.xml配置信息如下:

<context-param>

    <param-name>webAppRootKey</param-name>

    <param-value>muse.root</param-value>

</context-param>

<context-param>

    <param-name>log4jConfigLocation</param-name>

    <param-value>/WEB-INF/log4j.xml</param-value>

</context-param>  

<context-param>   

      <param-name>log4jRefreshInterval</param-name>   

      <param-value>6000</param-value>   

  </context-param>   

  

<listener>   

   <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>

</listener>  

1.2 log4j.properties配置

    所有相关的log4j.properties配置信息如下:

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender

log4j.appender.ROLLING_FILE.Threshold=INFO

log4j.appender.ROLLING_FILE.File=${muse.root}/logs/muse.log

log4j.appender.ROLLING_FILE.Append=true

log4j.appender.ROLLING_FILE.MaxFileSize=5000KB

log4j.appender.ROLLING_FILE.MaxBackupIndex=100

log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n 

源码赏析

2.1 Log4jConfigListener

    这是应用启动时即调用的监听类。该类不具体处理业务逻辑,直接调用Log4jWebConfigurer.initLogging()

public class Log4jConfigListener implements ServletContextListener {

public void contextInitialized(ServletContextEvent event) {

Log4jWebConfigurer.initLogging(event.getServletContext());

}

}

2.2 Log4jWebConfigurer

    这是一个便于在web环境定制log4j初始化的类。即log4j初始化前需要做的一些事情的处理类,当然它也包括调用处理具体初始化工作的类。

public abstract class Log4jWebConfigurer {

/** 该属性用来指定log4j 配置文件的路径。 */

public static final String CONFIG_LOCATION_PARAM = "log4jConfigLocation";

/** 该属性用来指定检查log4j 配置文件的间隔时间。 */

public static final String REFRESH_INTERVAL_PARAM = "log4jRefreshInterval";

/** 该属性用来指定是否设置web应用根目录环境变量。 */

public static final String EXPOSE_WEB_APP_ROOT_PARAM = "log4jExposeWebAppRoot";

/**

 * 初始化log4j,包括设置web应用根目录系统属性。

 */

public static void initLogging(ServletContext servletContext) {

if (exposeWebAppRoot(servletContext)) {

WebUtils.setWebAppRootSystemProperty(servletContext);

}

String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);

if (location != null) {

try {

if (!ResourceUtils.isUrl(location)) {

// 解决系统属性占位符的问题。

location = SystemPropertyUtils.resolvePlaceholders(location);

location = WebUtils.getRealPath(servletContext, location);

}

servletContext.log("Initializing log4j from [" + location + "]");

String intervalString = servletContext.getInitParameter(REFRESH_INTERVAL_PARAM);

if (intervalString != null) {

try {

long refreshInterval = Long.parseLong(intervalString);

Log4jConfigurer.initLogging(location, refreshInterval);

}

catch (NumberFormatException ex) {

throw new IllegalArgumentException("Invalid 'log4jRefreshInterval' parameter: " + ex.getMessage());

}

}

else {

Log4jConfigurer.initLogging(location);

}

}

catch (FileNotFoundException ex) {

throw new IllegalArgumentException("Invalid 'log4jConfigLocation' parameter: " + ex.getMessage());

}

}

}

/**

 * 返回是否进行web应用根目录系统属性设置。

 */

private static boolean exposeWebAppRoot(ServletContext servletContext) {

String exposeWebAppRootParam = servletContext.getInitParameter(EXPOSE_WEB_APP_ROOT_PARAM);

return (exposeWebAppRootParam == null || Boolean.valueOf(exposeWebAppRootParam));

}

}

2.3 WebUtils

    这个类是web应用程序的五花八门的工具箱。比如设置web应用目录系统属性等。

public abstract class WebUtils {

public static final String WEB_APP_ROOT_KEY_PARAM = "webAppRootKey";

/** Default web app root key: "webapp.root" */

public static final String DEFAULT_WEB_APP_ROOT_KEY = "webapp.root";

/**

 * 添加一个系统属性用于保存web应用根目录信息。系统属性键可以在web.xml文件的context-param节点定义。默认值为webapp.root

 * 如果不同的应用使用相同的该系统属性键则会报错。

 */

public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException {

Assert.notNull(servletContext, "ServletContext must not be null");

String root = servletContext.getRealPath("/");

if (root == null) {

throw new IllegalStateException(

    "Cannot set web app root system property when WAR file is not expanded");

}

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 && !StringUtils.pathEquals(oldValue, root)) {

throw new IllegalStateException(

    "Web app root system property already set to different value: '" +

    key + "' = [" + oldValue + "] instead of [" + root + "] - " +

    "Choose unique values for the 'webAppRootKey' context-param in your web.xml files!");

}

System.setProperty(key, root);

servletContext.log("Set web app root system property: '" + key + "' = [" + root + "]");

}

 

/**

 * 根据相对路径得到web应用下的绝对路径

 */

public static String getRealPath(ServletContext servletContext, String path) throws FileNotFoundException {

Assert.notNull(servletContext, "ServletContext must not be null");

if (!path.startsWith("/")) {

path = "/" + path;

}

String realPath = servletContext.getRealPath(path);

if (realPath == null) {

throw new FileNotFoundException(

"ServletContext resource [" + path + "] cannot be resolved to absolute file path - " +

"web application archive not expanded?");

}

return realPath;

}

}

2.4 Log4jConfigurer

    这是一个具体实现log4j配置的类。该类直接调用log4j组件的相关类进行日志记录器的配置。

public abstract class Log4jConfigurer {

public static final String CLASSPATH_URL_PREFIX = "classpath:";

public static final String XML_FILE_EXTENSION = ".xml";

/**

 * 从指定的配置文件路径来初始化log4j,该方法不支持定时检查配置文件变更功能。

 */

public static void initLogging(String location) throws FileNotFoundException {

String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);

URL url = ResourceUtils.getURL(resolvedLocation);

if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {

DOMConfigurator.configure(url);

}

else {

PropertyConfigurator.configure(url);

}

}

/**

 * 从指定的配置文件路径来初始化log4j,该方法支持定时检查配置文件变更功能。

 */

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("Log4j config file [" + resolvedLocation + "] not found");

}

if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {

DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);

}

else {

PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);

}

}

}

2.5 ResourceUtils

   这是一个用来解决文件资源定位的工具类。

public abstract class ResourceUtils {

public static final String CLASSPATH_URL_PREFIX = "classpath:";

/**

 * 返回指定的资源定位字符串是否是一个URL

 */

public static boolean isUrl(String resourceLocation) {

if (resourceLocation == null) {

return false;

}

if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {

return true;

}

try {

new URL(resourceLocation);

return true;

}

catch (MalformedURLException ex) {

return false;

}

}

}

1
1
分享到:
评论

相关推荐

    Spring项目中怎么配置log4j

    在Spring项目中配置log4j是一项基础且重要的工作,它能帮助我们记录应用程序的运行日志,便于调试、排查问题和性能分析。Log4j是一个广泛使用的Java日志框架,提供灵活的日志记录功能。接下来,我们将详细讲解如何在...

    log4j 源码包 日志包 2.11.0

    通过对Log4j 2.11.0源码的深入研究,开发者不仅可以掌握其基本用法,还能了解其背后的实现机制,从而更好地利用这一强大的工具,提升开发效率,优化系统性能。同时,源码学习也是提升编程技能的重要途径,能帮助...

    Log4j2、Fastjson、Log4j的BurpSuite插件亲测有效

    Log4j、Log4j2和Fastjson的安全性问题在过去曾引起广泛关注,例如Log4j2的CVE-2021-44228(也被称为Log4Shell漏洞),这是一个远程代码执行漏洞,影响了许多使用Log4j2的系统。这个插件可能就是为了检测和利用这些...

    Log4j工程官方源码

    这个压缩包文件包含的是Log4j的官方源码,对于开发者来说,能够直接导入到Eclipse中进行学习和研究,或者进行二次开发,具有很高的价值。下面将详细解释Log4j的核心概念、功能以及如何在Eclipse中使用这些源码。 1....

    Apache Log4j 2 源代码( apache-log4j-2.17.1-src.zip)

    Apache Log4j 2 源代码( apache-log4j-2.17.1-src.zip) 是对 Log4j 的升级,它比其前身 Log4j 1.x 提供了重大改进,并提供了 Logback 中可用的许多改进,同时修复了 Logback 架构中的一些固有问题。修复了安全漏洞...

    Log4j2效率测试源码

    - **资源消耗**:包括CPU、内存和磁盘I/O的使用情况,以了解Log4j2对系统资源的影响。 4. **优化策略** - **日志级别调整**:根据需求调整日志级别,减少不必要的日志记录,可以显著提升性能。 - **异步日志模式...

    log4j 1.2.8 jar 包含源码

    **Log4j 1.2.8 源码解析** Log4j 是一个广泛使用...通过深入研究 Log4j 1.2.8 的源码,开发者不仅可以更好地掌握日志管理,还可以提升对 Java 多线程、反射、配置解析等技术的理解,为今后的软件开发提供强大的支持。

    (源码)基于Spring Boot和Log4j2的TruthBean日志系统.zip

    # 基于Spring Boot和Log4j2的TruthBean日志系统 ## 项目简介 TruthBean日志系统是一个基于Spring Boot和Log4j2框架的高性能日志管理工具。它提供了丰富的日志级别和灵活的配置选项,适用于各种Java应用程序的日志...

    Apache Log4j 2 源代码( apache-log4j-2.17.1-src.tar.gz)

    Apache Log4j 2 源代码( apache-log4j-2.17.1-src.tar.gz) 是对 Log4j 的升级,它比其前身 Log4j 1.x 提供了重大改进,并提供了 Logback 中可用的许多改进,同时修复了 Logback 架构中的一些固有问题。修复了安全...

    apache-log4j-2.17.2-bin.tar

    此次发布的binaries版本包含了编译后的二进制文件,适用于那些不希望从源码编译但需要快速部署和更新Log4j的用户。 描述中提到的“解决了漏洞版本”指的是Log4j 2.x 在2021年末被发现了一个名为“Log4Shell”的高危...

    log4j 源码

    log4j 源代码 需要源码的请下载,java版,下载后自行关联。

    Log4j详解,详细讲解log4j的使用,和原理

    配置文件是 Log4j 的核心组件之一,通过配置文件可以灵活地控制日志的输出。 Log4j 的配置方式 Log4j 提供了多种配置方式,包括: * 通过配置文件来配置 Log4j * 通过 Java 代码来配置 Log4j Log4j 的输出级别 ...

    [简单]log4jdbc-log4j2配置简记

    标题中的“log4jdbc-log4j2配置简记”指的是在Java开发中使用log4jdbc-log4j2库来监控和记录SQL查询的过程。log4jdbc是一个开源项目,它允许开发者通过日志系统来追踪数据库操作,而log4j2是log4j的升级版,提供了更...

    新版本与旧版本log4j.jar包下载,附使用说明----.zip

    6. **apache-log4j-2.14.1-bin.zip**: 这可能是Log4j的完整二进制包,除了log4j.jar之外,还可能包含其他相关文件,如配置示例、文档、源码等。解压这个文件可以获取更多关于Log4j的资源,便于深入学习和调试。 综...

    apache-log4j-1.2.16.rar_apache log4j 1.2.16_log4j source code_lo

    Apache Log4j是Java平台上的一个著名日志记录框架,广泛应用于各种Java应用程序中,包括服务器、Web应用、企业级软件等。Log4j 1.2.16是该框架的一个版本,提供了丰富的日志功能,允许开发者灵活地控制日志信息的...

    log4j简单使用

    "源码"标签暗示我们将讨论Log4j的内部机制或如何查看和理解其代码,这对于学习和定制Log4j功能很有帮助。而"工具"标签则表明Log4j是一个开发者常用的工具,它的使用和配置是提高开发效率的关键。 **压缩包文件名称...

    maven-spring-mybatis小型项目开发环境(3)log4j集成

    在本项目中,"maven-spring-mybatis小型项目开发环境(3)log4j集成",我们将探讨如何在一个基于Maven、Spring和MyBatis的小型应用中整合Log4j日志框架。Log4j是Java应用程序广泛使用的日志记录工具,它提供灵活的日志...

    mybatis源码+练习代码+插件+log4j2+maven

    【标题】"mybatis源码+练习代码+插件+log4j2+maven" 提供的资源包是一个综合的学习资料集合,旨在帮助用户深入理解MyBatis这一流行持久层框架,同时涵盖日志管理工具Log4j2和项目构建工具Maven。以下是这些组件的...

    log4j-1.2.16.jar 源码包

    log4j-1.2.16.jar 源码包

    log4j各个版本源码

    log4j各个版本源码 1.2.8 1.2.15 1.2.17 2.3 这四个版本的源码 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录...

Global site tag (gtag.js) - Google Analytics