zoukankan      html  css  js  c++  java
  • SpringBoot如何与logback集成

    其实默认情况下,Spring Boot会自动用Logback作为应用日志框架,并用INFO级别输出到控制台。 可以由 spring-boot-starter-logging里面的依赖看出 

    那么问题来了, 在springboot中,日志是如何初始化的,怎么加载的日志配置文件,这个日志配置文件是否可以外置化?

    带着一系列的问题,查阅了springboot的官方文档及相关资料,总结如下:

    1. Logback在SpringBoot应用是如何初始化的

     Spring Boot启动的时候,由org.springframework.boot.context.logging.LoggingApplicationListener根据情况初始化并使用。

     1.1 如何加载logback相关配置文件

    在spring 初始化启动的过程中,会根据生命周期的不同阶段,发出对应的动作。这就是Spring ApplicationListener,设计基于观察者模式,而其中LoggingApplicationListener类便是负责logging日志框架的初始化操作。
    LoggingApplicationListener被配置在spring-boot-x.x.x.jar的spring.factories文件中,spring启动的时候会去读取这个文件。
       在Spring应用启动时会先获取到对应的日志实例。

      

    // org.springframework.boot.logging.LoggingApplicationListener
    private void onApplicationStartedEvent(ApplicationStartedEvent event) {
        this.loggingSystem = LoggingSystem
                .get(event.getSpringApplication().getClassLoader());
        this.loggingSystem.beforeInitialize();
    }

      检测和获取日志系统,检测的顺序定义在SYSTEMS中,最终通过反射创建LogbackLoggingSystem实例。

      

    // org.springframework.boot.logging.LoggingSystem
    public static LoggingSystem get(ClassLoader classLoader) {
        String loggingSystem = System.getProperty(SYSTEM_PROPERTY);// null
        if (StringUtils.hasLength(loggingSystem)) {
            if (NONE.equals(loggingSystem)) {
                return new NoOpLoggingSystem();
            }
            return get(classLoader, loggingSystem);
        }
        for (Map.Entry<String, String> entry : SYSTEMS.entrySet()) {
            if (ClassUtils.isPresent(entry.getKey(), classLoader)) {
                return get(classLoader, entry.getValue());
            }
        }
        throw new IllegalStateException("No suitable logging system located");
    }
    
    
    /**
     * A System property that can be used to indicate the {@link LoggingSystem} to use.
     */
    public static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();
    
    private static final Map<String, String> SYSTEMS;
    
    static {
        Map<String, String> systems = new LinkedHashMap<String, String>();
        systems.put("ch.qos.logback.core.Appender",
                "org.springframework.boot.logging.logback.LogbackLoggingSystem");
        systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory",
                "org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
        systems.put("java.util.logging.LogManager",
                "org.springframework.boot.logging.java.JavaLoggingSystem");
        SYSTEMS = Collections.unmodifiableMap(systems);
    }

       然后在ApplicationEnvironmentPreparedEvent之后进行logback的初始化

      

    private void onApplicationEnvironmentPreparedEvent(
            ApplicationEnvironmentPreparedEvent event) {
        if (this.loggingSystem == null) {
            this.loggingSystem = LoggingSystem
                    .get(event.getSpringApplication().getClassLoader());
        }
        initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
    }
    
        /**
     * Initialize the logging system according to preferences expressed through the
     * {@link Environment} and the classpath.
     * @param environment the environment
     * @param classLoader the classloader
     */
    protected void initialize(ConfigurableEnvironment environment,
            ClassLoader classLoader) {
        new LoggingSystemProperties(environment).apply();
        LogFile logFile = LogFile.get(environment);
        if (logFile != null) {
            logFile.applyToSystemProperties();
        }
        initializeEarlyLoggingLevel(environment);
        initializeSystem(environment, this.loggingSystem, logFile);
        initializeFinalLoggingLevels(environment, this.loggingSystem);
        registerShutdownHookIfNecessary(environment, this.loggingSystem);
    }

      重点看配置文件检测的过程。

    private void initializeWithConventions(
            LoggingInitializationContext initializationContext, LogFile logFile) {
            // 获取logback自己支持的配置文件
        String config = getSelfInitializationConfig();
        if (config != null && logFile == null) {
            // self initialization has occurred, reinitialize in case of property changes
            reinitialize(initializationContext);
            return;
        }
        // 如果没有则检测spring相关的logback配置
        if (config == null) {
            config = getSpringInitializationConfig();
        }
        if (config != null) {
            loadConfiguration(initializationContext, config, logFile);
            return;
        }
        loadDefaults(initializationContext, logFile);
    }

    logback自身配置文件的生效顺序。

    // org.springframework.boot.logging.logback.LogbackLoggingSystem
    @Override
    protected String[] getStandardConfigLocations() {
        return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy",
                "logback.xml" };
    }

    通过这里可以看到spring boot中支持的logback配置文件格式,就是在logback自配置文件(logback-test.xml, logback.xml等)基础上文件名后面加了“-spring”,如logback-test-spring, logback-spring等。

    /**
     * Return the spring config locations for this system. By default this method returns
     * a set of locations based on {@link #getStandardConfigLocations()}.
     * @return the spring config locations
     * @see #getSpringInitializationConfig()
     */
    protected String[] getSpringConfigLocations() {
        String[] locations = getStandardConfigLocations();
        for (int i = 0; i < locations.length; i++) {
            String extension = StringUtils.getFilenameExtension(locations[i]);
            locations[i] = locations[i].substring(0,
                    locations[i].length() - extension.length() - 1) + "-spring."
                    + extension;
        }
        return locations;
    }

    此外,Spring Boot使用JUnit时,如果没有配置SpringBootTest注解,日志系统根本不会得到初始化,会使用org.slf4j.impl.StaticLoggerBinder获取,如果在test/resource下面存在logback-test.xml则会生效,否则就使用系统默认的配置。如果配置了置SpringBootTest注解,则SpringBoot会正常的初始化,日志系统会正常加载。

    2.自定义日志配置

    由于日志服务一般都在ApplicationContext创建前就初始化了,它并不是必须通过Spring的配置文件控制。因此通过系统属性和传统的Spring Boot外部配置文件依然可以很好的支持日志控制和管理。

    Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项(下面会提到)。

    上面是默认的命名规则,并且放在src/main/resources下面即可。

    如果你即想完全掌控日志配置,但又不想用logback.xml作为Logback配置的名字,可以通过logging.config属性指定自定义的名字:

    logging.config=classpath:logging-config.xml

    虽然一般并不需要改变配置文件的名字,但是如果你想针对不同运行时Profile使用不同的日

    志配置,这个功能会很有用。

    参考:

      https://zhuanlan.zhihu.com/p/27874182

  • 相关阅读:
    js命名空间笔记
    css3兼容性问题归纳
    flexbox-CSS3弹性盒模型flexbox完整版教程
    JavaScript 预解析
    消除页面上的链接虚线框
    图片压缩之 PNG
    常见的前端优化技巧有哪些
    for-of循环和for-in循环的区别
    函数式编程初探
    js中同步与异步处理方法
  • 原文地址:https://www.cnblogs.com/whx7762/p/13265751.html
Copyright © 2011-2022 走看看