【Spring】通用日志框架和spring 5的日志技术新特性

目录

一、主流的log技术名词

1.1 log4j

1.2 JUL

1.3 JCL

1.4 SLF4J

1.4.1 绑定器

1.4.2 桥接器

1.5 log4j2

1.6 logback

1.7 simple-log

1.8 各种日志技术的关系和作用

二、spring日志技术分析

2.1 spring4日志技术实现

2.1 spring5日志技术实现


一、主流的log技术名词

1.1 log4j

maven依赖:


	log4j
	log4j
	1.2.17

可以不需要依赖第三方的技术,直接记录日志,但是必须要有配置文件。

 

使用:

// 引用的是log4j的Logger
import org.apache.log4j.Logger;
public class Log4j {
    public static void main(String[] args) {
        // 获取log4j的Logger对象,后面的括号是设置日志对象的唯一标识,可以自定义命名或当前类的Class
        Logger logger = Logger.getLogger(Log4j.class);
        logger.info("log4j");
    }
}

 

效果:

 

 

1.2 JUL

java自带的一个日志记录的技术,可以直接使用,不需要引用依赖包

 

使用:

// 这里引用的是JUL包下的Logger
import java.util.logging.Logger;
/**
 * 使用JUL记录日志不需要引用外部包,因为JUL是jdk自带的
 *
 * 不使用配置文件也可以使用
 */
public class JUL {
    public static void main(String[] args) {
        // JUL的Logger对象只能为其设置字符串命名,不能使用Class作为其标识
        Logger logger = Logger.getLogger("JUL");
        logger.info("jul");
    }
}

 

效果:

【Spring】通用日志框架和spring 5的日志技术新特性_第1张图片

 

 

1.3 JCL

jakarta Commons LoggingImpl

 

maven依赖:


	commons-logging
	commons-logging
	1.1.1

 

jcl它不直接记录日志,他是通过第三方记录日志比如log4j,jul等

 

如果使用jcl来记录日志,在没有log4j的依赖情况下,是用jul

如果有了log4依赖则优先使用使用log4j

 

使用:

// JCL的日志对象是Log
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JCL {
    public static void main(String[] args) {
        // JCL的日志对象是log,通过LogFactory得到的,括号里面设置的是日志对象的唯一标识,既可以使用当前类的class也可以自定义名字
        Log log = LogFactory.getLog("JCL");
        log.info("jcl");
    }
}

 

没有log4j依赖就会使用JUL:

【Spring】通用日志框架和spring 5的日志技术新特性_第2张图片

 

有log4j依赖就会使用log4j:

【Spring】通用日志框架和spring 5的日志技术新特性_第3张图片

 

JCL=Jakarta commons-logging ,是apache公司开发的一个抽象日志通用框架,本身不实现日志记录,但是提供了记录日志的抽象方法即接口(info,debug,error.......),底层通过一个数组存放具体的日志框架的类名,然后循环数组依次去匹配这些类名是否在app中被依赖了,如果找到被依赖的则直接使用,所以他有先后顺序

【Spring】通用日志框架和spring 5的日志技术新特性_第4张图片

上图为JCL中存放日志技术类名的数组,默认有四个,后面两个可以忽略,因为已经很老的技术了,现在不怎么用了总之使用JCL的话,它对日志技术的优先使用顺序是log4j>jul

【Spring】通用日志框架和spring 5的日志技术新特性_第5张图片

上图81行就是通过一个类名去load一个class,如果load成功则直接new出来并且返回使用只有项目引用了相应的依赖,类加载器才会把对应的Class加载入JVM,才可以使用forName将日志对象实例反射创建

【Spring】通用日志框架和spring 5的日志技术新特性_第6张图片

如果没有loadclass这循环第二个因为那四个类名是顺序存放在那个数组当中的,直到找到为止。

 

可以看到这里的循环条件必须满足result不为空,

也就是如果没有找到具体的日志依赖则继续循环,如果找到则条件不成立,不进行循环了。

 

使用JCL的优点:比如我们有一个项目,A模块用的是log4j,B模块用的是jul,如果直接使用这两个包记录日志,那么项目合并之后日记会出现不统一,非常混乱,不容易维护等问题。但是如果A模块使用JUL来调用log4j,B模块使用JUL来调用jul,那么两个模块合并之后就能很方便的统一管理,因为都是利用JUL中的Log作为中间件来进行日志管理的。所以使用一个中间件来管理项目日志的话,从长远角度看,对项目的扩展性是有好处的

 

spring4和spring5都内置了JCL

现在JCL已经不更新了,逐渐被淘汰了。现在slf4j取代了JCL,它据有更好的可拓展性

 

1.4 SLF4J

slf4j他也不记录日志,通过绑定器绑定一个具体的日志来完成日志记录

 

它引入了两个新的概念:绑定器(binder桥接器(bridge

它不再像JCL那样固定只能支持4中日志包,它可以通过绑定器更加灵活的拓展,每一种日志包有对应一个SLF4J绑定器,需要用什么日志包来实现记录日志的功能,就是用对应的绑定器就可以了。所以更加容易拓展,如果出现了新的日志类,只需要编写对应的绑定器就可以关联到SLF4J进行使用了。

 

使用:

maven依赖:



	org.slf4j
	slf4j-api
	1.7.25

 

1.4.1 绑定器

绑定器依赖



	org.slf4j
	slf4j-jdk14
	1.7.25




	org.slf4j
	slf4j-log4j12
	1.7.25




	org.slf4j
	slf4j-jcl
	1.7.25

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4J {
    public static void main(String[] args) {
        // JCL的日志对象是logger,也是通过LoggerFactory获得的,既可以使用当前类的class作为日志对象标识也可以使用自定义命名
        Logger logger = LoggerFactory.getLogger(SLF4J.class);
        logger.info("slf4j");
    }
}

 

【Spring】通用日志框架和spring 5的日志技术新特性_第7张图片

 

1.4.2 桥接器

桥接器指的是可以将一种日志类的实现转接到SLF4J上来,可以方便实现系统的日志统一管理.

比如使用了log4j的桥接器,那么A模块使用的是log4j,B模块使用的是slf4j,使用JUL绑定器,那么A模块的log4j日志系统就会转接到slf4j中,然后在从slf4j中使用JUL绑定器来完成日志记录,也就将log4j转换成了JUL。

 

桥接器依赖:



	org.slf4j
	jcl-over-slf4j
	1.7.25




	org.slf4j
	log4j-over-slf4j
	1.7.25

添加了桥接器之后,就可以使桥接器对应的日志记录实现转接到SLF4J上

 

缺点:

在项目变复杂的时候就有可能出现循环引用的问题,进而导致栈溢出。

比如:我将SLF4J使用一个绑定到JCL的绑定器,再使用一个JCL的桥接器将JCL再转接到SLF4J上,这样就会出现循环引用的问题

【Spring】通用日志框架和spring 5的日志技术新特性_第8张图片

 

1.5 log4j2

1.6 logback

1.7 simple-log

 

1.8 各种日志技术的关系和作用

 

【Spring】通用日志框架和spring 5的日志技术新特性_第9张图片

 

 

二、spring日志技术分析

 

2.1 spring4日志技术实现

spring4当中依赖的是原生的JCL,具体工作原理上面已经讲了

 

2.1 spring5日志技术实现

spring5使用的spring的JCL(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,也是采用一个优先的原则来选择日志包。

 

spring5将JCL改掉了,不再是原生的那样使用for循环,而是用一个switch选择。

 

源码:

在抽象类LogFactory中生成log对象

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的值来选择使用的日志包的。而logApi的值是在这个类的静态方法中生成的

static {
    logApi = LogFactory.LogApi.JUL;
    ClassLoader cl = LogFactory.class.getClassLoader();
    try {
		// 这里需要注意,这里是log4j2
        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) {
            }
        }
    }
}

 它获当前类加载器,然后按照一定的优先顺序依次根据类全限定名加载,如果项目引入了相应的依赖,将class加载入了JVM,那么就可以成功给logApi赋值。但是这里有一点需要注意,spring5中的JCL中引用的是log4j2,不是log4j,所以直接通过引用log4j的依赖包在spring5项目中是不起作用的,如果想要在spring5中使用log4j就得通过引用SLF4J,然后再通过引用log4j的绑定包来使用log4j,这是sping5与sping4在日志系统上最大的不同。

你可能感兴趣的:(Spring,Java)