spring4.0,spring5.0日志框架详解(包含部分源码解析)。

现阶段的日志框架有哪些?

  • log4j    直接记录日志
  • jcl      jcl他不直接记录日志,他是通过第三方记录日志(jul),如果使用jcl来记录日志,在没有log4j的依赖情况下,是用jul如果有了log4j则使用log4j 。jcl=Jakarta commons-logging ,是apache公司开发的一个抽象日志通用框架,本身不实现日志记录,但是提供了记录日志的抽象方法即接口(info,debug,error.......),底层通过一个数组存放具体的日志框架的类名,然后循环数组依次去匹配这些类名是否在app中被依赖了,如果找到被依赖的则直接使用,所以他有先后顺序,以下就是jcl中存放日志技术名的数组,默认有四个,后面两个可以 忽略。老版本的jdk才能用到第三四种日志实现。 jcl核心源码如下图所示,由图可知,该循环有个亮点,result==null 才循环执行适配日志框架,并按照事先定好数组顺序依次执行图二的代码通过反射创建日志实现返回,有兴趣的朋友可以看看

 

 

  • jul      java自带的一个日志记录的技术,直接使用
  • log4j2
  • slf4j    slf4j他也不记录日志,通过绑定器绑定一个具体的日志记录来完成日志记录(目前的主流日志框架门面)
  • logback
  • simple-log

画图分析下以上日志的简单工作机制

代码风

spring日志技术分析

spring4与spring5如下  注意5版本与4版本就只有pom文件不一样其他全部一样。

5版本pom文件 

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

4版本pom文件

    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.0.9.RELEASE</version>
    </dependency>
    <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
    </dependency>

 

log4j.properties

 log4j.rootLogger=Info, Console  
 #Console
 log4j.appender.Console=org.apache.log4j.ConsoleAppender
 log4j.appender.Console.Target=system.out
 log4j.appender.Console.layout=org.apache.log4j.PatternLayout
 log4j.appender.Console.layout.ConversionPattern=%d (%t) [%p - %l] %m%n
 

 Test测试类

package com.forewei.test;

import com.forewei.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


/**
 * @Author forewei
 * @date 2019-4-17 15:08
 */
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext
                = new AnnotationConfigApplicationContext(AppConfig.class);
        annotationConfigApplicationContext.start();
    }
}

 spring5输出 由图可知该输出肯定不是log4j 

spring4输出 可以看出已经用log4j打印日志了

spring4源码分析  有两种分析法。

1.通过断点如下源码截图可以判断出 spring4用的是log4j框架日志输出,点开log依赖可以看出该log是jcl框架,所以spring4底层用的是jcl实现。由于jcl实现的核心代码在上面已分析,这里就不做重复分析。

 2. 通过maven依赖确定

打开该项目maven依赖可以看出,spring4底层用的是jcl

spring5分析 

1.首先pom文件依赖图  由图可知也是用的jcl,但是这个jcl,应该和spring4一样会用log4j实现,但是仔细看下图的jcl依赖是spring的jcl依赖 由此可猜想spring5是把原生的jcl改了 所以导致这一结果。

2.源码分析 源码位置 org.apache.commons.logging.LogFactory   

这里我直接把重要代码部分贴出来并加上自己的注释

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.commons.logging;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.LoggerContext;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.spi.LocationAwareLogger;

public abstract class LogFactory {
    private static LogFactory.LogApi logApi;

    public LogFactory() {
    }

    public static Log getLog(Class<?> clazz) {
        return getLog(clazz.getName());
    }

    // 该方法判断使用哪种日志实现
    public static Log getLog(String name) {
        switch(logApi) {
        case LOG4J:
            return LogFactory.Log4jDelegate.createLog(name);
        case SLF4J_LAL:
            return LogFactory.Slf4jDelegate.createLocationAwareLog(name);
        case SLF4J:
            return LogFactory.Slf4jDelegate.createLog(name);
        default:
            return LogFactory.JavaUtilDelegate.createLog(name);
        }
    }

  // 该静态代码块初始化私有属性logApi默认的日志为JUL实现
  // 通过这段代码可以看出 spring5对jcl进行了改写,jcl源码上面已经分析不是这种流程
  // 由以下代码看出spring5改写的jcl支持log4j2,slf4j
  // 所以spring5在有log4j依赖时用的是默认的jul日志框架
    static {
        logApi = LogFactory.LogApi.JUL;
        ClassLoader cl = LogFactory.class.getClassLoader();

        try {
            cl.loadClass("org.apache.logging.log4j.spi.ExtendedLogger");
            logApi = LogFactory.LogApi.LOG4J;
        } catch (ClassNotFoundException var6) {
            try {
                cl.loadClass("org.slf4j.spi.LocationAwareLogger");
                logApi = LogFactory.LogApi.SLF4J_LAL;
            } catch (ClassNotFoundException var5) {
                try {
                    cl.loadClass("org.slf4j.Logger");
                    logApi = LogFactory.LogApi.SLF4J;
                } catch (ClassNotFoundException var4) {
                    ;
                }
            }
        }

    }

   
}

 终上所诉得出结论:

  • spring4日志技术实现      spring4当中依赖的是原生的jcl

 

  •  srping5日志技术实现     spring5使用的spring的jcl(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,采用循                                           环优先的原则

有问题的欢迎大家提问,博主有时间会解答。后续博主会出一些spring的源码技术分享文章!感谢大家的支持!

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章