日志之SLF4J解析(三)

一、前言:

本文只列出重要的知识点,具体如以下3点:
1.SLF4J是什么?
2.SLF4J如何使用?
3.SLF4J加载解析?

二、SLF4J是什么

SLF4J是qos-ch的开源项目slf4j,全称为 “ Simple Logging Facade for Java ”。
SLF4J解决了JUL动态查找的性能消耗,同时也解决了它,是现在使用最广的日志门面。

三、SLF4J如何使用

依赖导入
gradle

1
2
implementation 'org.slf4j:slf4j-api:1.7.30'
implementation 'org.slf4j:slf4j-simple:1.7.30'//SLF4J需要依赖一个日志实现

maven

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>

程序使用

1
2
3
4
5
6
7
8
9
10
import org.slf4j.LoggerFactory;

public class Logger {
static final org.slf4j.Logger LOG = LoggerFactory.getLogger(Logger.class);//获取日志对象

public static void main(String[] args) {
LOG.info("Hello JCL");//打印普通日志
LOG.info("{}",LOG.getClass());//打印日志对象类路径
}
}

程序执行输出

1
2
[main] INFO cn.xusc.Logger - Hello JCL
[main] INFO cn.xusc.Logger - class org.slf4j.impl.SimpleLogger

四、SLF4J加载解析

步骤一:程序代码加载

1
LoggerFactory.getLogger(Logger.class);//获取日志对象⬅️

步骤二:LoggerFactory

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
//获取日志实例
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
return logger;
}

public static Logger getLogger(String name) {
//获取日志工厂
ILoggerFactory iLoggerFactory = getILoggerFactory();⬅️
//获取日志实例
return iLoggerFactory.getLogger(name);⬅️
}

//获取日志工厂
public static ILoggerFactory getILoggerFactory() {
return getProvider().getLoggerFactory();⬅️
}

//获取提供者
static SLF4JServiceProvider getProvider() {
//一开始未初始化
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {//DCL(Double Check Lock)
INITIALIZATION_STATE = ONGOING_INITIALIZATION;//正在进行初始化
performInitialization();//执行初始化 -> SPI查找服务提供者1⃣️
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION://成功初始化
return PROVIDER;//提供者
case NOP_FALLBACK_INITIALIZATION://NOP回退初始化
return NOP_FALLBACK_FACTORY;//NOP回退工厂
case FAILED_INITIALIZATION://初始化失败
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);//抛出异常
case ONGOING_INITIALIZATION://正在初始化
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_PROVIDER;//SUBST提供者
}
throw new IllegalStateException("Unreachable code");//提供者获取异常
}

//获取日志工厂
public ILoggerFactory getLoggerFactory();⬅️

步骤三:SimpleServiceProvider(简单服务提供者实现)

1
2
3
4
5
6
7
8
9
10
11
12
//简单服务提供者
public class SimpleServiceProvider implements SLF4JServiceProvider {
private ILoggerFactory loggerFactory;
public ILoggerFactory getLoggerFactory() {
return loggerFactory;⬅️
}
@Override
public void initialize() {
//初始化简单日志工厂
loggerFactory = new SimpleLoggerFactory();
}
}

核心点1⃣️

把步骤二的执行初始化放到这里,主要是为了能更直观清晰的阅读整个流程。

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
//执行初始化
private final static void performInitialization() {
//查找并绑定
bind();⬅️
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
//验证是否为支持版本
versionSanityCheck();
}
}

//服务提供者查找并绑定
private final static void bind() {
try {
//查找所有服务提供者
List<SLF4JServiceProvider> providersList = findServiceProviders();⬅️
//验证服务提供者的唯一性
reportMultipleBindingAmbiguity(providersList);
//验证日志服务提供者是否存在
if (providersList != null && !providersList.isEmpty()) {
PROVIDER = providersList.get(0);//获取第一个服务提供者
PROVIDER.initialize();//调用服务提供者初始化流程
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;//设置成功标识
reportActualBinding(providersList);
} else {
//没有找到服务提供者,设置回退初始化标识、打印错误日志
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("No SLF4J providers were found.");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_PROVIDERS_URL + " for further details.");

//输出到可能存在的日志绑定
Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportIgnoredStaticLoggerBinders(staticLoggerBinderPathSet);
}
//提交绑定清理
postBindCleanUp();
} catch (Exception e) {
failedBinding(e);//异常绑定
throw new IllegalStateException("Unexpected initialization failure", e);
}
}

//查找所有的服务提供者
private static List<SLF4JServiceProvider> findServiceProviders() {
//SPI加载机制
ServiceLoader<SLF4JServiceProvider> serviceLoader = ServiceLoader.load(SLF4JServiceProvider.class);
List<SLF4JServiceProvider> providerList = new ArrayList<SLF4JServiceProvider>();
for (SLF4JServiceProvider provider : serviceLoader) {
providerList.add(provider);
}
return providerList;
}
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信