Spring Cloud 程序使用 logback 出错

先说结论

对于不使用 Spring Cloud Context 的 Spring Cloud 程序,最好把 Spring Cloud Context 禁用掉,因为如果不禁用的话会导致某些配置加载出错。禁用方法:
在 SpringBoot 主函数加上 System.setProperty("spring.cloud.bootstrap.enabled", "false"); 这句代码,示例如下:

@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("cn.xgq.operator.impl.mapper")
public class OperatorImplApplication {

    public static void main(String[] args) {
        // 禁用 Spring Cloud Context,要不然会导致 logback-spring.xml会被加载两次
        // Spring Cloud Context 详情:https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html
        System.setProperty("spring.cloud.bootstrap.enabled", "false");
        SpringApplication.run(OperatorImplApplication.class, args);
    }

}
问题复现

logback-spring.xml 配置 contextName 使用 application.yml 里面配置的 spring.application.name,log 文件路径使用了 logging.file.path,然后启动应用程序之后报错:
Failed to rename context [projectName_IS_UNDEFINED] as [operator] java.lang.IllegalStateException: Context has been already given a name

Exception in thread "main" java.lang.IllegalStateException: Logback configuration error detected: 
ERROR in ch.qos.logback.classic.joran.action.ContextNameAction - Failed to rename context [projectName_IS_UNDEFINED] as [operator] java.lang.IllegalStateException: Context has been already given a name
	at org.springframework.boot.logging.logback.LogbackLoggingSystem.loadConfiguration(LogbackLoggingSystem.java:169)
	at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:80)
	at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:60)
	at org.springframework.boot.logging.logback.LogbackLoggingSystem.initialize(LogbackLoggingSystem.java:118)
	at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:313)
	at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:288)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:246)
	at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:223)
	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:76)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
	at cn.xgq.operator.OperatorImplApplication.main(OperatorImplApplication.java:17)

logback-spring.xml 部分配置如下:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!-- 属性文件:在application.yml文件中找到对应的配置项 -->
    <springProperty scope="context" name="filePath" source="logging.file.path"/>
    <springProperty scope="context" name="projectName" source="spring.application.name"/>
    <contextName>${projectName}</contextName>

    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
    	<!-- appender 配置 -->
    </appender>

    <!--根据日志级别分离日志,分别输出到不同的文件-->
    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    	<!-- appender 配置 -->
    </appender>

    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- appender 配置 -->
    </appender>

    <root level="info">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileInfoLog"/>
        <appender-ref ref="fileErrorLog"/>
    </root>
</configuration>

application.yml 部分配置如下:

server:
  port: 9001

spring:
  application:
    name: operator
  datasource:
	# 数据源配置

logging:
  file:
    path: ./logs

mybatis:
  mapper-locations: classpath:mapper/*.xml

eureka:
  client:
    service-url: {defaultZone: http://localhost:9002/eureka/}
出现问题的原因

简单地说就是因为 Spring Cloud 程序有两个上下文,一个是“引导”上下文,负责从外部源加载配置属性和解密本地外部配置文件中的属性,从 bootstrap.yml 文件读取配置属性,另一个是主程序上下文,主要从application.yml 或者外部配置中心读取配置属性,然后这两个上下文都会读取 logback-spring.xml 的配置进行加载,但是由于本应用没有配置 bootstrap.yml,所以“引导”上下文加载 logback-spring.xml 的时候读取不到 projectNamefilePath 变量的值,所以这两个值就会使用 projectName_IS_UNDEFINEDfilePath_IS_UNDEFINED 作为值,然后等到主程序上下文去加载 logback-spring.xml 的时候因为这时候读取到的 contextName 和之前“引导”上下文加载出来的不一样,所以就报错了。

附:
Spring Cloud Context 官方说明
SpringCloud入门之应用程序上下文服务(Spring Cloud Context)详解

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值