log4j2.xml配置是否会被编程式配置覆盖?如何实现自动生效?
公共依赖库自动加载自定义log4j2配置解决方案
无法加载的核心原因
- 自定义
@Plugin未被log4j2正确扫描识别,缺少必要的插件索引文件 - 配置工厂优先级不足,被log4j2默认工厂或Spring Boot自带的log4j2配置逻辑覆盖
- Spring Boot日志初始化时机早于普通Bean加载,未触发自定义工厂的加载逻辑
具体修复步骤
1. 新增log4j2注解处理器,生成插件索引
log4j2不会自动扫描全类路径下的@Plugin注解,需要通过注解处理器在打包公共依赖时生成插件索引文件,在公共依赖的构建配置中添加以下内容:
Maven配置(pom.xml)
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>匹配你使用的log4j2版本</version> <optional>true</optional> </dependency> <!-- log4j2注解处理器,打包时自动生成插件索引 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>匹配你使用的log4j2版本</version> <classifier>annotations</classifier> <scope>provided</scope> </dependency> </dependencies>
打包后公共依赖jar包中会自动生成META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat文件,log4j2启动时会自动读取该文件识别自定义插件。
2. 调整配置工厂优先级&增加兼容逻辑
log4j2的@Order注解数值越小优先级越高,默认配置工厂的优先级为100,将自定义工厂优先级调整为高于默认值,同时可增加兼容逻辑:如果业务应用自身存在log4j2配置文件,优先使用应用自身的配置:
@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY) @Order(10) // 从原有的50改为10,优先级高于默认工厂 public class CustomConfigurationFactory extends ConfigurationFactory { static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) { // 你原有构建配置的代码保持不变 builder.setConfigurationName(name); builder.setStatusLevel(Level.DEBUG); builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL). addAttribute("level", Level.DEBUG)); AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE"). addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); appenderBuilder.add(builder.newLayout("PatternLayout"). addAttribute("pattern", "%d [%t]")); appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL).addAttribute("marker", "FLOW")); builder.add(appenderBuilder); builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG). add(builder.newAppenderRef("Stdout")). addAttribute("additivity", false)); builder.add(builder.newRootLogger(Level.DEBUG).add(builder.newAppenderRef("Stdout"))); return builder.build(); } @Override public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { // 新增兼容逻辑:如果存在外部配置源(应用自己的log4j2.xml/yml等),返回null交给下一个配置工厂处理 if (source != null && (source.getFile() != null || source.getURI() != null)) { return null; } return getConfiguration(loggerContext, source.toString(),null); } @Override public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) { ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder(); return createConfiguration(name, builder); } @Override protected String[] getSupportedTypes() { return new String[] {"*"}; } }
3. 适配Spring Boot初始化逻辑(可选,极端场景下使用)
如果以上配置仍不生效,可通过Spring Boot SPI在日志初始化前强制指定自定义配置工厂:
- 在公共依赖的
resources/META-INF/spring.factories中添加:
org.springframework.context.ApplicationListener=你的包名.CustomLogConfigListener
- 实现监听器,在Spring Boot启动最早期设置系统属性:
public class CustomLogConfigListener implements ApplicationListener<ApplicationStartingEvent> { @Override public void onApplicationEvent(ApplicationStartingEvent event) { // 日志初始化前指定自定义配置工厂的全类名 System.setProperty("log4j2.configurationFactory", "你的包名.CustomConfigurationFactory"); } }
验证方式
启动应用时添加JVM参数-Dlog4j2.debug=true,查看控制台输出的初始化日志,确认存在CustomConfigurationFactory加载记录,且日志格式符合你配置的%d [%t]规则即可。
内容的提问来源于stack exchange,提问作者Saurabh kumar Gupta
相关产品推荐
相关产品推荐

