美文网首页
完全掌控logging的生与死(一)LoggingApplica

完全掌控logging的生与死(一)LoggingApplica

作者: 牧羊人刘俏 | 来源:发表于2020-12-27 18:37 被阅读0次

    在SpringBoot里面的spring.factories里面有注册一个org.springframework.boot.context.logging.LoggingApplicationListener,这个监听器起到了加载具体的logging的能力。
    我们分别看下在sb启动的不同的阶段,此listener所做的事情,在开始启动的阶段,如下

    private void onApplicationStartingEvent(ApplicationStartingEvent event) {
                    //根据classloader加载日志模块,哪个加载成功,就使用哪个
            this.loggingSystem = LoggingSystem
                    .get(event.getSpringApplication().getClassLoader());
                   //执行具体的logging组件的回调方法-beforeInitialize
            this.loggingSystem.beforeInitialize();
        }
    

    而对于LoggingSystem.get(event.getSpringApplication().getClassLoader())方法,

        /**
         * Detect and return the logging system in use. Supports Logback and Java Logging.
         * @param classLoader the classloader
         * @return the logging system
         */
        public static LoggingSystem get(ClassLoader classLoader) {
                    //是否有自己配置日志模块
            String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
            if (StringUtils.hasLength(loggingSystem)) {
                if (NONE.equals(loggingSystem)) {
                    return new NoOpLoggingSystem();
                }
                           //如果有配置,根据配置的loggingSystemClass反射去初始化
                return get(classLoader, loggingSystem);
            }
                    //如果没有,那么系统默认按照,logback,log4j,jul的顺序去加载对应的class,哪个加载成功就使用哪个日志模块,我本地使用了logback,故而加载出来loggingSystem就是logback。(slf4j+logback)是spring推荐的标准的logging配置。
            return SYSTEMS.entrySet().stream()
                    .filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
                    .map((entry) -> get(classLoader, entry.getValue())).findFirst()
                    .orElseThrow(() -> new IllegalStateException(
                            "No suitable logging system located"));
        }
    
        private static LoggingSystem get(ClassLoader classLoader, String loggingSystemClass) {
            try {
                Class<?> systemClass = ClassUtils.forName(loggingSystemClass, classLoader);
                return (LoggingSystem) systemClass.getConstructor(ClassLoader.class)
                        .newInstance(classLoader);
            }
            catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
        }
    

    在上一步主要是确定使用的logging组件(一下默认使用的组件是logback),确定了组件之后,接下来就是对选择的组件进行初始化的操作。那在什么时候进行初始话的操作呢,肯定是在所有的系统变量加载完成之后,根据配置的系统变量来对组件进行初始化了。所以初始化发生在如下

    private void onApplicationEnvironmentPreparedEvent(
                ApplicationEnvironmentPreparedEvent event) {
            if (this.loggingSystem == null) {
                this.loggingSystem = LoggingSystem
                        .get(event.getSpringApplication().getClassLoader());
            }
            initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
        }
    
    protected void initialize(ConfigurableEnvironment environment,
                ClassLoader classLoader) {
            new LoggingSystemProperties(environment).apply();
            LogFile logFile = LogFile.get(environment);
            if (logFile != null) {
                logFile.applyToSystemProperties();
            } 
                    //初始化sb的logging级别
            initializeEarlyLoggingLevel(environment);
                    //根据环境变量初始化系统
            initializeSystem(environment, this.loggingSystem, logFile);
                    //确定最终的logging等级
            initializeFinalLoggingLevels(environment, this.loggingSystem);
                    //注册shutdown的钩子方法
            registerShutdownHookIfNecessary(environment, this.loggingSystem);
        }
    

    第三步,将应用启动起来之后,将loggingSystem作为bean注册到了容器,后期我们会根据这个bean做动态化的扩展和增强(重点打钩)

        private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
            ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
                    .getBeanFactory();
            if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
                beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
            }
        }
    

    而onContextClosedEvent() 和onApplicationFailedEvent可以忽略,主要是应用启动失败的话,调用this.loggingSystem.cleanUp()。做一些清理工作。

    相关文章

      网友评论

          本文标题:完全掌控logging的生与死(一)LoggingApplica

          本文链接:https://www.haomeiwen.com/subject/wvetoktx.html