解决 Log4j 多 classloader 重复加载问题

什么是 Log4j

Log4j 是 Apache 的一个开源项目,通过使用 Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

Log4j 配置(xml和property两种)

1、Logger 完成日志信息的处理

定义输出的层次和决定信息是否输出 DEBUG < INFO < WARN < ERROR

2、Appender 设置日志信息的去向

常用的:

1
2
3
4
5
6
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppener(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志讯息以串流格式发送到任意指定的地方)
org.apache.log4j.JdbcAppender(将日志讯息保存到数据库中)

3、Layout 设置日志信息的输出样式

layout有以下几种:

1
2
3
4
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.SimpleLayout(包含日志讯息的级别和讯息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、执行绪、类别等讯息)
org.apache.log4j.PatterLayout(可以灵活地指定布局格式)

4、配置文件 log4j.properties或log4j.xml

log4j.properties实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
log4j.logger.com.jjm.util=INFO, A1,A2  
log4j.logger.com.jjm.dao=DEBUG, A1

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n

log4j.appender.A2=org.apache.log4j.RollingFileAppender
log4j.appender.A2.File=sshdemo.log
log4j.appender.A2.MaxFileSize=500KB
log4j.appender.A2.MaxBackupIndex=1
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n

log4j.xml实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="A1" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="sshdemo2.log" />
<param name="MaxFileSize" value="1MB" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n" />
</layout>
</appender>
<appender name="A2" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n" />
</layout>
</appender>
<logger name="com.jjm.dao">
<level value="DEBUG" />
<appender-ref ref="A1" />
</logger>
<root>
<priority value="DEBUG" />
<appender-ref ref="A2" />
</root>
</log4j:configuration>

Log4j 中 log4j.properties 和 log4j.xml 的加载顺序

if the user has not specified the log4j.configuration property, we search first for the file “log4j.xml” and then “log4j.properties”

当用户没有设置log4j.configuration属性,则首先查找log4j.xml,然后查找log4j.properties。log4j.properties已经不再推荐使用了。

出现的问题: Log4j 多classloader重复加载

1
2
3
4
5
6
7
log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable.
log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by
log4j:ERROR [java.net.URLClassLoader@17494c8] whereas object of type
log4j:ERROR "org.apache.log4j.xml.DOMConfigurator" was loaded by [weblogic.utils.classloaders.ChangeAwareClassLoader@7f99b7 finder: weblogic.utils.classloaders.CodeGenClassFinder@e61868 annotation: _auto_generated_ear_@UserManager].
log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator].
log4j:WARN No appenders could be found for logger (com.minstone.cas.client.util.CommonUtils).
log4j:WARN Please initialize the log4j system properly.

网上有几种方法:

在 Log4j 的配置文件中增加配置

让log4j忽略由不同的classloader的初始化这个问题。在log4j的配置文件中增加以下代码即可。

log4j.xml:

1
-XX:MaxPermSize=512m -Xmx512m -Denv=DEV <span style="color:#CC0000">-Dlog4j.ignoreTCL=true</span>

log4j.properties:

1
log4j.ignoreTCL=true

修改初始化 Log4j 线程的 classloader

由于 Log4j 会用当前线程上下文中的 classloader 去初始化配置,虽然 Log4j 的 jar 是由 URLClassLoader 加载进来的,但是加载的线程还是在 WebApp 中的,还 是WebApp 的 ClassLoader,所以会出现上面的提示信息。因此,我们至要通过下面代码:

1
Thread.currentThread().setContextClassLoader(urlclassLoader);

将当前线程的上下文loader改为沙箱的ClassLoader即可。

Maven:修改 pom.xml 文件

若是在 Maven 环境下配置出现的问题,则在 pom.xml

1
2
3
4
5
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.4.2</version>
</dependency>

<dependency> 内加入代码,如下:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.4.2</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>

总结

最后是指导人发了 MyEclipse 说项目其实是用这个 IDE 编程实现的,配置过程中就没出现问题,一路畅通无阻…………………………

文章目录
  1. 1. 什么是 Log4j
    1. 1.1. Log4j 配置(xml和property两种)
    2. 1.2. Log4j 中 log4j.properties 和 log4j.xml 的加载顺序
  2. 2. 出现的问题: Log4j 多classloader重复加载
    1. 2.1. 在 Log4j 的配置文件中增加配置
    2. 2.2. 修改初始化 Log4j 线程的 classloader
    3. 2.3. Maven:修改 pom.xml 文件
  3. 3. 总结

20170221-log4j/

本页二维码