博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码日志分析
阅读量:2065 次
发布时间:2019-04-29

本文共 6633 字,大约阅读时间需要 22 分钟。

1.jdk自带的java util logging,即jul

日志输出格式:
从源码可以看到jul的Logger是个具体的类
2.apache的commons-logging,即jcl
输出结果,没有任何配置
从表面看起来是使用的jul,实际上是什么样的,查看源码Log是一个接口,而不是具体的实现类

看LogFactory.getLog源码,实际上是有一个数组,里面放了4种日志打印方式
然后通过反射获取数组里的对象

private Log createLogFromClass(String logAdapterClassName, String logCategory, boolean affectState) throws LogConfigurationException {        if (isDiagnosticsEnabled()) {            this.logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'");        }        Object[] params = new Object[]{logCategory};        Log logAdapter = null;        Constructor constructor = null;        Class logAdapterClass = null;        ClassLoader currentCL = this.getBaseClassLoader();        while(true) {            this.logDiagnostic("Trying to load '" + logAdapterClassName + "' from classloader " + LogFactory.objectId(currentCL));            String resourceName;            try {                if (isDiagnosticsEnabled()) {                    resourceName = logAdapterClassName.replace('.', '/') + ".class";                    URL url;                    if (currentCL != null) {                        url = currentCL.getResource(resourceName);                    } else {                        url = ClassLoader.getSystemResource(resourceName + ".class");                    }                    if (url == null) {                        this.logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found.");                    } else {                        this.logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'");                    }                }                Class c;                try {                    c = Class.forName(logAdapterClassName, true, currentCL);                } catch (ClassNotFoundException var15) {                    String msg = var15.getMessage();                    this.logDiagnostic("The log adapter '" + logAdapterClassName + "' is not available via classloader " + LogFactory.objectId(currentCL) + ": " + msg.trim());                    try {                        c = Class.forName(logAdapterClassName);                    } catch (ClassNotFoundException var14) {                        msg = var14.getMessage();                        this.logDiagnostic("The log adapter '" + logAdapterClassName + "' is not available via the LogFactoryImpl class classloader: " + msg.trim());                        break;                    }                }                constructor = c.getConstructor(this.logConstructorSignature);                Object o = constructor.newInstance(params);                if (o instanceof Log) {                    logAdapterClass = c;                    logAdapter = (Log)o;                    break;                }                this.handleFlawedHierarchy(currentCL, c);            } catch (NoClassDefFoundError var16) {                resourceName = var16.getMessage();                this.logDiagnostic("The log adapter '" + logAdapterClassName + "' is missing dependencies when loaded via classloader " + LogFactory.objectId(currentCL) + ": " + resourceName.trim());                break;            } catch (ExceptionInInitializerError var17) {                resourceName = var17.getMessage();                this.logDiagnostic("The log adapter '" + logAdapterClassName + "' is unable to initialize itself when loaded via classloader " + LogFactory.objectId(currentCL) + ": " + resourceName.trim());                break;            } catch (LogConfigurationException var18) {                throw var18;            } catch (Throwable var19) {                LogFactory.handleThrowable(var19);                this.handleFlawedDiscovery(logAdapterClassName, currentCL, var19);            }            if (currentCL == null) {                break;            }            currentCL = this.getParentClassLoader(currentCL);        }        if (logAdapterClass != null && affectState) {            this.logClassName = logAdapterClassName;            this.logConstructor = constructor;            try {                this.logMethod = logAdapterClass.getMethod("setLogFactory", this.logMethodSignature);                this.logDiagnostic("Found method setLogFactory(LogFactory) in '" + logAdapterClassName + "'");            } catch (Throwable var13) {                LogFactory.handleThrowable(var13);                this.logMethod = null;                this.logDiagnostic("[INFO] '" + logAdapterClassName + "' from classloader " + LogFactory.objectId(currentCL) + " does not declare optional method " + "setLogFactory(LogFactory)");            }            this.logDiagnostic("Log adapter '" + logAdapterClassName + "' from classloader " + LogFactory.objectId(logAdapterClass.getClassLoader()) + " has been selected for use.");        }        return logAdapter;    }

当能找到log4j的情况,则使用log4j打印,加入log4j的jar包和log4j.properties

log4j.rootLogger=INFO,stdout,logfilelog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.outlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%nlog4j.appender.logfile=org.apache.log4j.FileAppenderlog4j.appender.logfile.File=D:/test.loglog4j.appender.logfile.layout=org.apache.log4j.PatternLayoutlog4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n

再输出结果,则使用的时loj4j打印

根据源码分析出:使用jcl打印日志的时,当项目中有log4j的jar包和配置的时候,优先使用log4j,没有log4j的时候使用jul(jdk14或jdk13),jdk13目前也没用了,最后是Simple Log(目前基本已不使用)

jcl的缺陷,扩展性差,只有数组里提供的四种日志类型,spring5.0已下则依赖的是apache的commons-logging

而spring5.0以上在不再使用apache原生的commons-logging,而是自己扩展了jcl,apache原生的commons-logging已停止更新不建议使用
3.spring的jcl

来源于spring的jcl的jar包

spring5以上支持的日志顺序log4j2->slf4j_lal(1.3版本及以后)->slf4j(1.3版本之前)->默认jul,当匹配不到时使用默认的jul

可以发现spring5是不支持log4j,支持log4j2的,那为什么在我们的项目中会看到可以使用log4j呢?一种情况使用的是spring5已下的版本,如果是spring5是因为我们使用的slf4j然后通过绑定器实现使用log4j打印日志。

增加slf4j的jar包slf4j-api和slf4j与log4j的的绑定器slf4j-log4j12(log4j 1.x的版本)

org.slf4j
slf4j-log4j12
1.7.28
org.slf4j
slf4j-api
1.7.28
log4j
log4j
1.2.17

发现可以正常使用log4j的方式打印

去掉绑定器slf4j-log4j12,则报错
以上分析可知:从日志扩展角度和移植行,建议使用slf4j接口,它为每个日志的实现类都对应了一个绑定器,换日志打印时比较方便,扩展性好,不建议在代码中直接使日志具体实现类。如log4j,jul,也不建议使用apache原生jcl,已停止更新且扩展性差
还有一个问题是slf4j log4j死循环的问题:
项目加入slf4j-log4j12的jar包,又加入log4j-over-slf4j的jar包,会导致死循环

究其本质的原因是: log4j代理给slf4j --> slf4j绑定到log4j,所以循环于此,所以会报错

 

 

 

 

 

 

 

 

 

转载地址:http://yswmf.baihongyu.com/

你可能感兴趣的文章
03. 交换机的Telnet远程登陆配置
查看>>
04. 交换机的端口聚合配置
查看>>
05. 交换机划分Vlan配置
查看>>
06. 三层交换机实现VLAN间路由
查看>>
07. 快速生成树协议
查看>>
08. 路由器的基本配置和Talent配置
查看>>
09. 路由器单臂路由配置
查看>>
10. 路由器静态路由配置
查看>>
路由器动态ip获取不到的处理办法
查看>>
微信小程序-调用-腾讯视频-解决方案
查看>>
giuhub搭建及常用操作
查看>>
phpStudy安装yaf扩展
查看>>
密码 加密 加盐 常用操作记录
查看>>
TP 分页后,调用指定页。
查看>>
Oracle数据库中的(+)连接
查看>>
java-oracle中几十个实用的PL/SQL
查看>>
PLSQL常用方法汇总
查看>>
详细介绍Oracle sqlplus命令
查看>>
几个基本的 Sql Plus 命令 和 例子
查看>>
PLSQL单行函数和组函数详解
查看>>