
本文针对log4j 1迁移至log4j 2后,应用仍尝试加载log4j 1配置的常见问题提供解决方案。即使表面上已移除所有log4j 1依赖和配置,某些隐蔽的旧配置(如`web.xml`中的spring log4j集成配置)仍可能导致错误。教程将指导读者识别并清除这些残留配置,确保log4j 2正常运行。
Log4j 1 到 Log4j 2 迁移中的常见陷阱
将JavaEE项目从Log4j 1.x版本迁移到Log4j 2.x是一个常见的升级任务,旨在利用Log4j 2带来的性能提升、模块化设计和更强大的功能。然而,尽管表面上对Maven pom.xml、代码和日志配置文件进行了更新,许多开发者仍会遇到应用程序在启动时尝试加载Log4j 1配置的问题。这通常表现为控制台输出Log4j 1特有的警告和错误信息,指示它正在寻找log4j.xml或解析Log4j 1的配置标签。
识别Log4j 1残留配置的症状
当Log4j 1的旧配置机制仍在运行时,通常会伴随以下类型的日志输出:
log4j:WARN Continuable parsing error 2 and column 31 log4j:WARN L'élément racine de document "Configuration" doit correspondre à la racine DOCTYPE "null". log4j:WARN Continuable parsing error 2 and column 31 log4j:WARN Le document nest pas valide : aucune grammaire détectée. log4j:ERROR DOM element is - not a <log4j:configuration> element.
这些警告和错误信息明确指出,Log4j 1的XML解析器正在尝试处理一个不符合其DTD(如log4j:configuration)的配置,或者找不到预期的log4j.xml文件。这表明即使您已将log4j.xml替换为log4j2.xml,并移除了Log4j 1的依赖,某些组件仍在激活Log4j 1的初始化逻辑。
初步排查步骤
在深入挖掘潜在的隐藏配置之前,应确保已完成以下基础迁移工作:
-
更新Maven依赖:
- 移除所有Log4j 1.x相关的依赖(如log4j:log4j)。
- 添加Log4j 2.x核心依赖(org.apache.logging.log4j:log4j-api和org.apache.logging.log4j:log4j-core)。
- 如果使用了SLF4J,确保引入Log4j 2的SLF4J桥接器(org.apache.logging.log4j:log4j-slf4j2-impl,取决于SLF4J版本)。
- 检查是否存在传递性依赖引入Log4j 1。可以使用mvn dependency:tree命令查看依赖树,并为引入Log4j 1的依赖添加exclusion。例如:
<dependency> <groupId>some.group</groupId> <artifactId>some-artifact</artifactId> <version>1.0.0</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency>
-
更新日志配置文件:
- 将log4j.xml(或.properties)文件替换为log4j2.xml(或.properties、.json、.yml)。
- 确保log4j.dtd文件已被移除,因为Log4j 2不再使用它。
-
代码层面更新:
- 更新所有Log4j 1 API调用(如org.apache.log4j.Logger)为Log4j 2 API(如org.apache.logging.log4j.Logger)或SLF4J API。
发现隐藏的Log4j 1配置:web.xml
在JavaEE或Spring Web项目中,一个常见的被忽视的Log4j 1残留配置位于web.xml文件中。这些配置通常用于在Web应用程序启动时初始化Log4j 1,尤其是在与Spring框架集成时。
问题通常出在以下web.xml片段:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.xml</param-value>
</context-param>
<context-param>
<param-name>log4jExposeWebAppRoot</param-name>
<param-value>false</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>解析这些配置:
- log4jConfigLocation:这是一个context-param,由Spring的Log4jConfigListener读取,用于指定Log4j 1配置文件的位置。当其值为classpath:log4j.xml时,它明确指示应用程序去查找并加载Log4j 1的配置文件。
- log4jExposeWebAppRoot:另一个context-param,通常与Log4jConfigListener配合使用,用于控制是否将Web应用程序根路径暴露为系统属性,以便Log4j 1配置文件可以使用它。
- org.springframework.web.util.Log4jConfigListener:这是Spring框架提供的一个监听器,专门用于在Web应用程序启动时初始化Log4j 1。它的存在是导致Log4j 1初始化逻辑被激活的根本原因。
解决方案:
对于已迁移到Log4j 2的项目,这些web.xml中的配置是完全多余且有害的。Log4j 2有其自身的初始化机制,通常通过Log4jServletContainerInitializer(在Servlet 3.0+环境中自动发现)或直接通过类路径扫描log4j2.xml来完成。因此,直接移除web.xml中上述所有Log4j 1相关的context-param和listener配置即可解决问题。
移除后的web.xml片段将不再包含这些内容。
确保Log4j 2正确初始化
在移除Log4j 1的旧配置后,您需要确保Log4j 2能够正确初始化。
-
Servlet 3.0+环境: 如果您的Web容器支持Servlet 3.0及以上版本,并且您已正确引入log4j-web依赖,Log4j 2通常会自动通过Log4jServletContainerInitializer来初始化,无需额外的web.xml配置。
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.19.0</version> <!-- 确保与log4j-core版本一致 --> </dependency> - 非Web环境或旧版Servlet: Log4j 2默认会在类路径中查找名为log4j2.xml、log4j2.json、log4j2.yaml或log4j2.properties的配置文件。确保您的log4j2.xml文件位于src/main/resources目录下,以便它能被正确加载。
总结与注意事项
Log4j 1到Log4j 2的迁移不仅仅是替换依赖和配置文件那么简单,还需要对应用程序中所有可能引用旧日志框架的地方进行彻底检查。特别是对于复杂的JavaEE项目,web.xml中隐藏的Spring Log4j 1集成配置是导致迁移失败的一个常见原因。
关键注意事项:
- 彻底性: 确保不仅移除Log4j 1的直接依赖,还要检查传递性依赖,并排除它们。
- 配置文件: 确保所有旧的Log4j 1配置文件(如log4j.xml、log4j.properties)及其相关的DTD都被移除或替换。
- Web配置: 务必检查web.xml,移除任何与Log4jConfigListener或log4jConfigLocation相关的配置。
- 测试: 迁移后进行彻底的测试,确保日志功能正常,且没有出现Log4j 1相关的错误或警告。
通过细致的排查和清理,您可以成功地将项目迁移到Log4j 2,享受其带来的各项优势。










