spring源码日志技术分析

spring5.和spring4.日志技术实现

新建一个项目,引入spring5的pom依赖。

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>

可以看到spring5默认使用了jcl包,测试代码:

1
2
3
4
public static void main(String[] args){
AnnotationConfigApplicationContext cx = new AnnotationConfigApplicationContext(App.class);
cx.start();
}

运行后得到日志信息:

1
2
三月 04, 2019 8:55:15 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@bebdb06: startup date [Wed Mar 04 20:55:15 CST 2020]; root of context hierarchy

引入log4j的包,再运行,日志发现没任何变化。

如果把spring5改为spring4,进行相同的测试,运行后的日志有变化。

通过查看文档得知:spring5使用的spring的jcl(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,采用switch循环优先的原则。

20200420224148

spring4当中依赖的是原生的jcl(原生的jcl就是如果有log4j就会优先使用)。

20200420224203

spring jcl分析:

1
2
3
public AbstractApplicationContext() {
//实例化
this.logger = LogFactory.getLog(this.getClass());

获取分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//定义
private static enum LogApi {
LOG4J,
SLF4J_LAL,
SLF4J,
JUL;

private LogApi() {
}
}

private static LogFactory.LogApi logApi;

//初始化值
static {
//默认使用jul
logApi = LogFactory.LogApi.JUL;
ClassLoader cl = LogFactory.class.getClassLoader();

//看能否加载对应的类
try {
//如果能加载log2j2
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) {
}
}
}

}

//获取日志对象
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}

public static Log getLog(String name) {
switch(logApi) {
case LOG4J://使用的log4j2而不是log4j
return LogFactory.Log4jDelegate.createLog(name);
case SLF4J_LAL:
return LogFactory.Slf4jDelegate.createLocationAwareLog(name);
case SLF4J:
return LogFactory.Slf4jDelegate.createLog(name);
default:
//默认使用jul
return LogFactory.JavaUtilDelegate.createLog(name);
}
}

此时,如果引入log4j2的包,日志会走log4j2。

总结:

1
2
spring5使用的spring的jcl(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,采用switch循环优先的原则。
spring4当中依赖的是原生的jcl(原生的jcl就是如果有log4j就会优先使用)。