apollo的飢餓加載配置錯誤導致springboot日志配置不成功


先來看springboot中apollo的配置:

 

 不仔細看或者對apollo配置不熟的人來說是很難看出配置錯在哪的,正確配置應該是如下:

 

 eagerLoad配置錯,會導致springboot日志框架初始化時apollo的配置時還未加載成功,導致apollo配置的日志DEBUG級別沒起效果。

雖然是團隊哪位大佬的一不小心的疏忽,但是還是花了不少時間找問題。其他項目同樣配置可以DEBUG級別有效,可以確認apollo的日志配置是正確的,應該是配置加載出了問題。

下面我們就來分析下springboot的日志初始化過程:

首先找到springboot的日志初始化入口:

我們在spring-boot包中找到LoggingApplicationListener這個類,這個是spring的事件監聽器,主要代碼如下:

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationStartingEvent) {
            onApplicationStartingEvent((ApplicationStartingEvent) event);
        }
        else if (event instanceof ApplicationEnvironmentPreparedEvent) {
            onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
        }
        else if (event instanceof ApplicationPreparedEvent) {
            onApplicationPreparedEvent((ApplicationPreparedEvent) event);
        }
        else if (event instanceof ContextClosedEvent
                && ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
            onContextClosedEvent();
        }
        else if (event instanceof ApplicationFailedEvent) {
            onApplicationFailedEvent();
        }
    }

 

日志初始化主要是onApplicationEnvironmentPreparedEvent事件,也就是環境准備好事件,代表着所以配置已經加載,比如放apollo的配置。

    private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        if (this.loggingSystem == null) {
            this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
        }
        initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
    }

 

然后看initialize方法:

    protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
        new LoggingSystemProperties(environment).apply();
        this.logFile = LogFile.get(environment);
        if (this.logFile != null) {
            this.logFile.applyToSystemProperties();
        }
//初始化前的日志級別 initializeEarlyLoggingLevel(environment);
//初始化 initializeSystem(environment,
this.loggingSystem, this.logFile);
//初始化后的日志級別 initializeFinalLoggingLevels(environment,
this.loggingSystem); registerShutdownHookIfNecessary(environment, this.loggingSystem); }

 

我們主要看下initializeSystem方法,這個方法也主要是調用system.initialize方法,這里我們使用的是logback,所以system是LogbackLoggingSystem。

下面我們看LogbackLoggingSystem的initialize方法:

    @Override
    public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
        LoggerContext loggerContext = getLoggerContext();
        if (isAlreadyInitialized(loggerContext)) {
            return;
        }
        super.initialize(initializationContext, configLocation, logFile);
        loggerContext.getTurboFilterList().remove(FILTER);
        markAsInitialized(loggerContext);
        if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
            getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring '" + CONFIGURATION_FILE_PROPERTY
                    + "' system property. " + "Please use 'logging.config' instead.");
        }
    }

 

這個方面里面核心是super.initialize,調用父類的initialize方法,父類是AbstractLoggingSystem,這些代碼都是放在spring-boot包的logging下。

 

 

然后我們看AbstractLoggingSystem的initialize方法:

    @Override
    public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
        if (StringUtils.hasLength(configLocation)) {
            initializeWithSpecificConfig(initializationContext, configLocation, logFile);
            return;
        }
        initializeWithConventions(initializationContext, logFile);
    }
configLocation是沒設置值的,所以會進入initializeWithConventions方法:
    private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
//獲取logback自己支持的配置,搜索logback-test.groovy,logback-test.xml,logback.groovy,logback.xml這些文件 String config
= getSelfInitializationConfig(); if (config != null && logFile == null) { // self initialization has occurred, reinitialize in case of property changes reinitialize(initializationContext); return; } if (config == null) {
//獲取spring支持的配置,搜索logback-test-spring.groovy,logback-test-spring.xml,logback-spring.groovy,logback-spring.xml這些文件 config
= getSpringInitializationConfig(); } if (config != null) {
//搜索到logback的配置文件,就就在,這里面主要是解析logback的過程,就不分析了。 loadConfiguration(initializationContext, config, logFile);
return; } loadDefaults(initializationContext, logFile); }

 

然后我們回到最開始分析的initializeFinalLoggingLevels方法:

    private void initializeFinalLoggingLevels(ConfigurableEnvironment environment, LoggingSystem system) {
        if (this.springBootLogging != null) {
            initializeLogLevel(system, this.springBootLogging);
        }
        setLogLevels(system, environment);
    }

 

setLogLevels這個方法是設置日志級別,我們繼續往下看:
    protected void setLogLevels(LoggingSystem system, Environment environment) {
        if (!(environment instanceof ConfigurableEnvironment)) {
            return;
        }
//獲取到所以的配置 Binder binder
= Binder.get(environment); Map<String, String[]> groups = getGroups(); binder.bind(LOGGING_GROUP, STRING_STRINGS_MAP.withExistingValue(groups));
//從配置中獲取所以logging.level開頭的配置,並轉換為map Map
<String, String> levels = binder.bind(LOGGING_LEVEL, STRING_STRING_MAP).orElseGet(Collections::emptyMap); levels.forEach((name, level) -> { String[] groupedNames = groups.get(name); if (ObjectUtils.isEmpty(groupedNames)) {
//遍歷logging.level,設置每個配置的級別 setLogLevel(system, name, level); }
else { setLogLevel(system, groupedNames, level); } }); }

 

 map結構如下:

"org.springframework.cloud.sleuth" -> "INFO"
"com.xxx" -> "DEBUG"
"org.springframework" -> "INFO"

當初找到DEBUG不起效,就是在這個方法中發現levels根本沒值,正常的里面是有如上的map結果,然后就感覺配置沒讀到,繼續查看environment對象,果然apollo的配置是沒讀到,確定apollo的飢餓加載有問題,最后對比springboot的apollo配置鎖定配置出錯。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM