之前在文章 使用Nacos简化SpringBoot配置(所有配置放入到Nacos中) 中有实现一个 ​​EnvironmentPostProcessor​​的扩展接口;

但是发现日志并没有打印出来, 然后就跟着源码找了一下问题;

问题原因:


在SpringBoot加载的过程中 ​​EnvironmentPostProcessor​​ 的执行比较早; 这个时候日志系统根本就还没有初始化;
所以在此之前的日志操作都不会有效果;


看看日志系统加载的时机

日志系统初始化的地方 ​​LoggingApplicationListener.onApplicationEnvironmentPreparedEvent()​

【Log日志】在日志系统初始化之前如何打印日志_日志

知道了日志初始化的时候是在这里;那也就知道了加载时机;那么是在哪里开始加载的呢? 我们来分析一下

首先找到 spring.factories 配置文件里面的配置;

【Log日志】在日志系统初始化之前如何打印日志_加载_02

找到被加载的地方; 具体为事件​​ApplicationEnvironmentPreparedEvent​​通知到对应的监听者的;可以看到; ​​ConfigFileApplicationListener​​ > ​​LoggingApplicationListener​​ ; 前面比后面先加载

【Log日志】在日志系统初始化之前如何打印日志_初始化_03

看看SpringBoo整体的加载时机 【SpringBoot】SpringBoot启动流程图和扩展点说明

【Log日志】在日志系统初始化之前如何打印日志_日志_04

从上面的图中可以了解到

在 ​​ConfigFileApplicationListener​​执行的时候 会去 ​​spring.factories​​ 中加载所有 ​​EnvironmentPostProcessor​​并执行​​postProcessEnvironment方法​​; 这个时候 ​​LoggingApplicationListener​​还没有被执行;说明日志系统还没有被初始化; 自然而然的 在这之前的所有日志操作都是无效的;

解决方案


使用 DeferredLog 缓存日志;并在合适的时机回放日志


public class NacosEnvPostProcessor implements EnvironmentPostProcessor, ApplicationListener<ApplicationEvent>, Ordered {

/**
* 这个时候Log系统还没有初始化 使用DeferredLog来记录 并在onApplicationEvent进行回放
* */
private static final DeferredLog LOGGER = new DeferredLog();
@Override
public int getOrder() {
return 0;
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
LOGGER.info("打印日志");
}

@Override
public void onApplicationEvent(ApplicationEvent event) {
LOGGER.replayTo(NacosEnvPostProcessor.class);
}
}

不要忘记了在​​spring.factorie​​ 配置

org.springframework.boot.env.EnvironmentPostProcessor=com.xxx.NacosEnvPostProcessor
org.springframework.context.ApplicationListener=com.xxx.NacosEnvPostProcessor


【Log日志】在日志系统初始化之前如何打印日志_日志_05