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 才循环执行适配日志框架,并按照事先定好数组顺序依次执行图二的代码通过反射创建日志实现返回,有兴趣的朋友可以看看spring4.0,spring5.0日志框架详解(包含部分源码解析)。_第1张图片

 

 spring4.0,spring5.0日志框架详解(包含部分源码解析)。_第2张图片

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

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

spring4.0,spring5.0日志框架详解(包含部分源码解析)。_第3张图片

spring日志技术分析

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

5版本pom文件 

        
            org.springframework
            spring-context
            5.0.9.RELEASE
        
        
            log4j
            log4j
            1.2.17
        

4版本pom文件

    
            org.springframework
            spring-context
            4.0.9.RELEASE
    
    
            log4j
            log4j
            1.2.17
    

 

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.0,spring5.0日志框架详解(包含部分源码解析)。_第4张图片

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

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

spring4.0,spring5.0日志框架详解(包含部分源码解析)。_第6张图片 2. 通过maven依赖确定

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

spring4.0,spring5.0日志框架详解(包含部分源码解析)。_第7张图片

spring5分析 

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

spring4.0,spring5.0日志框架详解(包含部分源码解析)。_第8张图片

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的源码技术分享文章!感谢大家的支持!

 

 

 

 

 

你可能感兴趣的:(spring)