Spring Boot 2.0下配置Log4j2下的错误问题分析与解决

Posted 星朝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot 2.0下配置Log4j2下的错误问题分析与解决相关的知识,希望对你有一定的参考价值。

环境介绍

Spring Boot 2.0.2 Java 8

任务描述

由于Spring Boot 2.0 默认情况下是使用logback作为日志系统的,这里希望切换到log4j2.

pom.xml内容定义

这里在pom.xml新增了spring-boot中的日志组件

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

第一次运行碰到的错误信息

直接运行,在控制台中报出如下的错误信息:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/DevSpace/M2Space/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/DevSpace/M2Space/org/apache/logging/log4j/log4j-slf4j-impl/2.10.0/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
13:55:11.713 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Included patterns for restart : []
13:55:11.721 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Excluded patterns for restart : [/spring-boot-actuator/target/classes/, /spring-boot-devtools/target/classes/, /spring-boot/target/classes/, /spring-boot-starter-[w-]+/, /spring-boot-autoconfigure/target/classes/, /spring-boot-starter/target/classes/]
13:55:11.722 [main] DEBUG org.springframework.boot.devtools.restart.ChangeableUrls - Matching URLs for reloading : [file:/D:/CodeSpace/photobuyapi/target/classes/]
Logging system failed to initialize using configuration from ‘classpath:log4j2.xml‘
java.lang.IllegalStateException: Logback configuration error detected: 
ERROR in ch.qos.logback.core.joran.spi.Interpreter@3:17 - no applicable action for [properties], current ElementPath  is [[configuration][properties]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:35 - no applicable action for [property], current ElementPath  is [[configuration][properties][property]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@7:16 - no applicable action for [appenders], current ElementPath  is [[configuration][appenders]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@9:53 - no applicable action for [Console], current ElementPath  is [[configuration][appenders][Console]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@10:92 - no applicable action for [PatternLayout], current ElementPath  is [[configuration][appenders][Console][PatternLayout]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@16:91 - no applicable action for [RollingRandomAccessFile], current ElementPath  is [[configuration][appenders][RollingRandomAccessFile]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@17:106 - no applicable action for [PatternLayout], current ElementPath  is [[configuration][appenders][RollingRandomAccessFile][PatternLayout]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@18:23 - no applicable action for [Policies], current ElementPath  is [[configuration][appenders][RollingRandomAccessFile][Policies]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@19:45 - no applicable action for [TimeBasedTriggeringPolicy], current ElementPath  is [[configuration][appenders][RollingRandomAccessFile][Policies][TimeBasedTriggeringPolicy]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@21:48 - no applicable action for [DefaultRolloverStrategy], current ElementPath  is [[configuration][appenders][RollingRandomAccessFile][DefaultRolloverStrategy]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@25:14 - no applicable action for [loggers], current ElementPath  is [[configuration][loggers]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@27:58 - no applicable action for [logger], current ElementPath  is [[configuration][loggers][logger]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@30:74 - no applicable action for [logger], current ElementPath  is [[configuration][loggers][logger]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@31:42 - no applicable action for [appender-ref], current ElementPath  is [[configuration][loggers][logger][appender-ref]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@32:46 - no applicable action for [appender-ref], current ElementPath  is [[configuration][loggers][logger][appender-ref]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@36:28 - no applicable action for [root], current ElementPath  is [[configuration][loggers][root]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@37:42 - no applicable action for [appender-ref], current ElementPath  is [[configuration][loggers][root][appender-ref]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@38:46 - no applicable action for [appender-ref], current ElementPath  is [[configuration][loggers][root][appender-ref]]
 at org.springframework.boot.logging.logback.LogbackLoggingSystem.loadConfiguration(LogbackLoggingSystem.java:166)
 at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithSpecificConfig(AbstractLoggingSystem.java:67)
 at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:57)
 at org.springframework.boot.logging.logback.LogbackLoggingSystem.initialize(LogbackLoggingSystem.java:114)
 at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:269)
 at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:237)
 at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:200)
 at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:173)
 at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
 at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
 at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
 at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
 at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:74)
 at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
 at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:358)
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:317)
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255)
 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243)
 at com.jd.ai.cv.api.PubAPIApplication.main(PubAPIApplication.java:17)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

从上述日志中,可以发现,默认使用了logback-classic的日志组件,所以和这里引用的logging组件发生了冲突。

注释掉logback

在pom.xml中注释掉logback.xml中的logback的引用类库,在Eclipse中的Dependency Hierarchy中搜索logback类库,右击选中,选择Exclude Maven Artifact…操作,就将exclude规则写到了pom.xml中了。
技术图片
从上图中可以看到,这里是Logging组件本身对于logback有依赖,这里应该是从Logging中将logback的依赖包Exclude掉,但是…..问题出现了。在pom.xml,将看到如下的Exclude规则:

<dependency>
     <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
         <exclusions>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                </exclusion>
         </exclusions>
</dependency>
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

虽然从图中看到的和pom.xml中的实际Exclude规则是不一致的,实际的Exclude规则被放到了Web的组件中了, 那为什么会是这样的?
那只能有一种解释,Web组件实质上依赖于Logging组件的,在组件的设计中,只是将logback类包放入到了Logging组件中,但是Spring Boot中的Web组件是直接使用logback类库的。所以,Exclude规则是发生在了Spring Boot的Web组件中。

第二次执行碰到的问题

在Exclude了logback之后,重新执行整个项目,希望可以正常启动项目,结果问题依然,只是错误信息不同了。。。。。

Exception in thread "main" java.lang.StackOverflowError
at org.apache.logging.log4j.util.StackLocator.getCallerClass(StackLocator.java:112)
at org.apache.logging.log4j.util.StackLocator.getCallerClass(StackLocator.java:125)
at org.apache.logging.log4j.util.StackLocatorUtil.getCallerClass(StackLocatorUtil.java:55)
at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:42)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:46)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:29)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)
at org.apache.logging.slf4j.SLF4JLoggerContext.getLogger(SLF4JLoggerContext.java:39)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:37)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:29)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:52)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:29)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)
at org.apache.logging.slf4j.SLF4JLoggerContext.getLogger(SLF4JLoggerContext.java:39)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:37)
at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:29)
at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:52)
at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:29)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)

从错误信息中可以发现,发生死循环了,哪里来的死循环呢?是Log4j的实例化过程中死循环。

问题的解决

在经历了若干个分钟的无奈思考之后,于是想尝试一下。由于Web组件中直接依赖了Logging组件,导致了整个问题的发生,是否可以直接将Logging组件从Web中Exclude掉,然后在pom.xml中直接引入Logging组件。是否就可以解决问题?
大胆假设,小心求证,来吧。

<dependency>
    <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
         <exclusions>
            <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
            <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
    </exclusions>
</dependency>

如果上述的方法依然无法解决您的问题,就基于如下的方式,直接排除掉logging的组件:

<dependency>
          <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

重新执行

系统正常启动,问题已解决。

总结

这里的问题症结点在logging组件与log4j2组件在Spring Boot体系中的彼此冲突问题,这里只能Exclude掉其中一个,方可正常地启动系统。

以上是关于Spring Boot 2.0下配置Log4j2下的错误问题分析与解决的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + Log4j2 日志框架配置 (Maven)

Spring Boot 2.0 教程 - 配置详解

Spring Boot 应用系列 5 -- Spring Boot 2 整合logback

Spring boot 2.0 - 为用户配置

spring boot log4j2配置

如何使用 spring boot 2.0 配置 redis ttl