• 分析spring4和spring5日志中的不同


      日志在工作中起到关键作用,我们经常使用它来打印关键信息,方便分析,或者是输出错误信息,用于bug排查,spring中同样使用了日志进行信息的输出,但是spring4和spring5之间的日志又有些不同,接下来我们就进行一些分析。

    1. 各种日志技术简述:  

        log4j,jul,jcl,log4j2,slf4j

        我们先把他们展示出来,以免引用错误。

      1.1 log4j

       使用log4j需要引入log4j的配置文件log4j.properties,内容简配一下:

    log4j.rootLogger = info,stdout
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target = System.out
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

      pom文件中只引入log4j所需要的jar包

      

      程序也写的简单一点,输出日志就行:

      

       结果:

      

      日志是输出的。

     1.2JUL

      JUL 是jdk自带的,所以pom文件中不需要引入任何包,直接撸代码:

      

       结果:

      

       日志输出格式我们不再做改变,记住log4j和jul的日志输出格式,后面有用到。

     1.3:JCL

      pom中引入所需要的包:

           

       撸代码:

      

      结果:

      

       呜呼,这个日志输出是不是很眼熟呀,长得很像上面JUL打印出来的日志,难道他们之间有什么不可描述的事情?所以最帅的我准备打开JCL的源码一探究竟。

      从上面代码中的LogFactory的getLog方法下手,进去:

      

      木得意思,就一行代码,那就再深一点,进入getInstance()中,

      

       第一行代码看着像是拿到了log,不过老哥我已经帮大家踩过坑了,debug走了一遍,第一行代码执行后,Log 依然是null,所以我们继续往下走,进入到

    this.newInstance()方法中,有点长,就酱紫:

    protected Log newInstance(String name) throws LogConfigurationException {
            Log instance = null;
    
            try {
                Object[] params;
                if (this.logConstructor == null) {
                    instance = this.discoverLogImplementation(name);
                } else {
                    params = new Object[]{name};
                    instance = (Log)this.logConstructor.newInstance(params);
                }
    
                if (this.logMethod != null) {
                    params = new Object[]{this};
                    this.logMethod.invoke(instance, params);
                }
    
                return instance;
            } catch (LogConfigurationException var5) {
                throw var5;
            } catch (InvocationTargetException var6) {
                Throwable c = var6.getTargetException();
                if (c != null) {
                    throw new LogConfigurationException(c);
                } else {
                    throw new LogConfigurationException(var6);
                }
            } catch (Throwable var7) {
                throw new LogConfigurationException(var7);
            }
        }

      这段代码差一点就比我的长处还长呢,所以我又帮大家debug了一遍,在第一个if判断 之后执行的这个方法 this.discoverLogImplementation(name);就是我们要找的,再深入,在

    discoverLogImplementation()这个方法中,我找到了这段代码:

      

      result属性就是我们需要返回的Log,循环条件中有一个classesToDiscover,并且还把他的值传给了this.createLogFromClass()方法,点击看看他是什么,

    String[] classesToDiscover = new String[]{"org.apache.commons.logging.impl.Log4JLogger", 
                              "org.apache.commons.logging.impl.Jdk14Logger",
                              "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
                              "org.apache.commons.logging.impl.SimpleLog"};

      这个数组里面找到了 org.apache.commons.logging.impl.Jdk14Logger,这不就是我们的JUL 吗?再想到刚刚的for循环,我们很容易理解,JCL就是循环这个数组,一次获取Log,知道Log 不为null为止,为了验证我们的猜想,

    我们可以引入log4j的jar包和配置文件,其他代码不做修改,这样按照数组顺序,应该打印出来log4j的日志。

          

    果然,在有log4j的情况下,JCL按照刚刚那个数组,顺序加载log,知道Log不为null。

      由此可以看出,JCL起到的是一个中间商赚差价的作用,在有log4j的时候使用log4j,否则使用JUL

    2 Sring4 的日志体系

      上面说了那么多,只是介绍了一部分日志技术,接下来我们开始分别分析spring4和spring5的日志体系。

      2.1 构建spring4项目

      采用java+注解的方式快速构建,pom中只引入spring-context包

      

      运行下面的代码,可以看到有日志输出

      

       

       找到打印日志的地方,debug模式下,查看输出日志的Log是什么log

      

      可以看出是jdk14Logger,这个在JCL中说过,这个指的是JUL,也就是说在默认spring日志体系下,采用的是JUL,

      接下来,我们按照之前的方法引入log4j,debug运行上面的程序,再次查看日志类型

      

      额,这次在增加log4j jar包和配置文件的情况下,spring4有使用了log4j,这么像JCL呢,木错,让我们在idea中打开spring4的日志依赖结构:

      

      common-logging 这不就是JCL使用到的包吗,可以看出,Spring4使用的是原生的JCL,所以在有log4j的时候使用log4j打印日志,没有的时候使用JUL打印日志。

    3.Spring5日志体系

      线上依赖结构图:

      

       答题结构没变,只是原来common-logging ,换成了spring-jcl,看名字就知道是spring自造的包,jcl,更是标注了,它使用的是JCL日志体系。

      所以还是看源码吧。

      按照之前的经验,我们只用debug找到spring内部一个Log,看看他的产生方式和类型。这次我给大家找了AbstractApplicationContext里面找到产生Log的地方

      

      进入这个方法的getLog()中,一直深入,不要怜惜spring,找到LogAdapter中的createLog()方法

      

       可以看出来spring5中对日志的生产,不在像原生JCL中那样使用一个数组,然后进行循环产生,这里用到的是Switch case,这个关键字段LogApi又是在哪一部分赋值的呢?看图

      

       Duang ,没错是在静态代码块中赋的值,为了验证,我们准备用其中提到的log4j2验证(注意:log4j不行,因为这里的switch没有log4j选项),首先我们准备log4j2的配置文件

      

    <Configuration status="WARN">
    
    <Appenders>
    
    <Console name="Console" target="SYSTEM_OUT">
    
    <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    
    </Console>
    
    </Appenders>
    
    <Loggers>
    
    <Root level="debug">
    
    <AppenderRef ref="Console"/>
    
    </Root>
    
    </Loggers>
    
    </Configuration>

      然后准备pom

      

       代码还是这一行,直接运行:

               

      结果有日志打印出来了

      

       所以,在spring5中,依然使用的是JCL,但是不是原生的,是经过改造的JCL,默认使用的是JUL,而原生JCL中默认使用的是log4j.

      好了,就酱紫,求轻拍,大家中秋快乐。

      

      

      

      

          

          

          

  • 相关阅读:
    django quick start
    LiveWriter插入高亮代码插件介绍 基于SyntaxHighighter
    自动填充脚本使用及注意事项
    连接池错误
    Python3.3官方教程中文翻译1:开胃菜
    [译]科学计算可视化在andriod与ios实现的工具
    EXTGWT、GWT与EXTJS之间的关系
    Python3.3官方教程中文翻译2:使用Python解释器
    SAS9.1.3安装过程中反复出现重启动挂起的解决方案
    Sqlite 插入数据异常(乱码),看看是不是数据类型的错误
  • 原文地址:https://www.cnblogs.com/wudb/p/11511266.html
Copyright © 2020-2023  润新知