spring5和spring4 日志新特性

使用现象对比

我们看看我们经常使用的框架日志是怎么玩的? 这一段时间一直在研究这个日志相关的东西,这些比较流行的框架如何玩?

我们先看看spring4 和 spring 5运行时的区别:

spring 4

没有增加log4j
在这里插入图片描述
增加log4j
在这里插入图片描述

spring5.0.9.RELEASE

没有增加log4j
在这里插入图片描述
增加log4j
在这里插入图片描述

总结: spring4 默认实现jcl 打印日志,增加log4j后便使用log4j打印日志
spring5 默认实现jcl打印日志,但是(jcl已经修改),增加log4j后也不会使用log4j打印日志:

spring5低版本日志是开启的,高版本默认是关闭的(我使用5.3.9这个版本的时候发现的,具体哪个版本开始改的就不知道了没纠结)

 if (this.logger.isDebugEnabled()) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Refreshing " + this);
            } else {
                this.logger.debug("Refreshing " + this.getDisplayName());
            }
        }
org.apache.commons.logging.LogAdapter.JavaUtilLog#isDebugEnabled
public boolean isDebugEnabled() {
这个值恒为false
            return this.logger.isLoggable(Level.FINE);
        }

spring4 和 5 依赖关系图

在这里插入图片描述
在这里插入图片描述

spring4 日志实现原码

org.apache.commons.logging.impl.LogFactoryImpl#discoverLogImplementation
真正的log方法创建入口:

private Log discoverLogImplementation(String logCategory) throws LogConfigurationException {
        if (isDiagnosticsEnabled()) {
            this.logDiagnostic("Discovering a Log implementation...");
        }

        this.initConfiguration();
        Log result = null;
        String specifiedLogClassName = this.findUserSpecifiedLogClassName();
        if (specifiedLogClassName != null) {
            if (isDiagnosticsEnabled()) {
                this.logDiagnostic("Attempting to load user-specified log class '" + specifiedLogClassName + "'...");
            }

            result = this.createLogFromClass(specifiedLogClassName, logCategory, true);
            if (result == null) {
                StringBuffer messageBuffer = new StringBuffer("User-specified log class '");
                messageBuffer.append(specifiedLogClassName);
                messageBuffer.append("' cannot be found or is not useable.");
                this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Log4JLogger");
                this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Jdk14Logger");
                this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Jdk13LumberjackLogger");
                this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.SimpleLog");
                throw new LogConfigurationException(messageBuffer.toString());
            } else {
                return result;
            }
        } else {
            if (isDiagnosticsEnabled()) {
                this.logDiagnostic("No user-specified Log implementation; performing discovery using the standard supported logging implementations...");
            }

            for(int i = 0; i < classesToDiscover.length && result == null; ++i) {
                result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
            }

            if (result == null) {
                throw new LogConfigurationException("No suitable Log implementation");
            } else {
                return result;
            }
        }
    }


for(int i = 0; i < classesToDiscover.length && result == null; ++i) {
result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
}

private static final 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.Log4JLogger 就默认使用 org.apache.commons.logging.impl.Jdk14Logger 这个是jdk自带的,我们的java代码都是使用的jdk所以后面的基本不会使用,

由此可以看出spring4 我们引入log4i就会被加载

通过分析jcl的代码可以得到:
jcl本身不实现日志记录,但是提供了记录日志的抽象方法即接口(info,debug,error…)
底层通过一个数组存放具体的日志框架的类名,然后循环数组依次去匹配这些类名是否在项目中被依赖了,如果找到被依赖的则直接使用,所以他有先后顺序。
下图为jcl中存放日志技术类名的数组,默认有四个,后面两个可以忽略。

jcl特点:
他不直接记录日志,他是通过第三方记录日志(jul)。
jcl是一个接口,默认有4个log实现类。

spring5 源码

Spring4当中依赖jcl,即Spring4当中采用的日志技术是jcl:commons-logging,即默认使用jul;加入log4j依赖和配置,即可切换为log4j
Spring5当中也是使用了jcl:spring-jcl,是重写为了jul框架。spring5使用的spring的jcl(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,采用循环优先的原则。

 public static Log getLog(Class<?> clazz) {
        return getLog(clazz.getName());
    }
org.apache.commons.logging.LogFactory#getLog(java.lang.String)
//name 是使用日志的类名,我们再找一下logApi 这个变量的初始化
    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);
        }
    }

private static LogFactory.LogApi logApi;

从下面的代码我们可以看出,spring5开始不再支持log4j而是直接支持log4j2

static {
        logApi = LogFactory.LogApi.JUL;
        ClassLoader cl = LogFactory.class.getClassLoader();

//第一步找log4j2
//第二步找slf4j
//第三步使用默认的jcl
        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) {
                }
            }
        }

    }

从上面spring5的源码可以看到,spring5使用的日志是spring-jcl,默认是jul,然后会依次加载log4j2,slf4j。在都加载不到的情况下,就使用默认的jul日志技术了。
因为spring5使用的是log4j2,所以在加入了log4j的依赖和配置文件,是不生效的。

这样我们就可以想想一下,目前不是spring5不支持log4j,但是我们的项目就是用的log4j又怎么办,
使用桥接器:

<dependencies>

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

        <!--slf4j依赖(可省略)-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version>
        </dependency>

        <!--slf4jbind绑定器,将slf4j绑定到log4j(已经包含了slf4j和log4j的依赖)-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.32</version>
        </dependency>


    </dependencies>

这样就实现了使用log4j;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值