文章目录
官网
Simple Logging Facade for Java (SLF4J) 用作各种日志记录框架(e.g. java.util.logging、logback、log4j)的简单外观或抽象,允许最终用户在部署时插入所需的日志记录框架 时间。
请注意,启用 SLF4J 的库意味着仅添加一个强制依赖项,即 slf4j-api.jar。 如果在类路径上找不到绑定/提供程序,则 SLF4J 将 default 为 no-operation 实现。
SLF4J user manual:https://slf4j.org/manual.html
集成步骤
POM依赖
为了实现 SLF4J 与 Log4j 2.x 的集成,您需要添加以下 Maven 依赖:
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.2</version>
</dependency>
<!-- log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.2</version>
</dependency>
slf4j-api
: SLF4J 的核心 API,用于定义日志接口。log4j-api
和log4j-core
: Log4j 2.x 的核心库,提供日志记录功能。log4j-slf4j-impl
: Log4j 2 与 SLF4J 的适配器,用于将 SLF4J 的日志调用转发给 Log4j 2。
使用案例
第一步:编写 Log4j2 的配置文件
创建一个 log4j2.xml
配置文件,设置 Log4j 2 的日志级别和输出格式。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<!-- 控制台输出 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L --->>> %m%n"/>
</Console>
<!-- 文件输出 -->
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}.log">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<!-- 根日志级别设置为info -->
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
第二步:在代码中使用 SLF4J
在代码中通过 LoggerFactory.getLogger()
获取日志记录器实例,并使用 SLF4J API 记录日志。
package com.artisan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* slf4j 与 log4j2 集成
*
*/
public class Slf4jLog4j2Example {
private static final Logger logger= LoggerFactory.getLogger(Slf4jLog4j2Example.class);
public static void main(String[] args){
logger.trace("Slf4jLog4j2Example This is a trace message");
logger.debug("Slf4jLog4j2Example This is a debug message");
logger.info("Slf4jLog4j2Example This is an info message");
logger.warn("Slf4jLog4j2Example This is a warning message");
logger.error("Slf4jLog4j2Example This is an error message");
}
}
原理分析
1. 获取对应的 ILoggerFactory
SLF4J 通过 StaticLoggerBinder
类来绑定日志实现。在 log4j-slf4j-impl
包中,StaticLoggerBinder
是关键类,它返回 Log4jLoggerFactory
,这是 Log4j 2.x 集成的核心。
- 步骤 1.1:SLF4J 使用类加载器加载
org/slf4j/impl/StaticLoggerBinder.class
,找到log4j-slf4j-impl
包中的绑定类。 - 步骤 1.2:创建
StaticLoggerBinder
实例后,通过getSingleton()
获取ILoggerFactory
,该工厂返回Log4jLoggerFactory
实例。
StaticLoggerBinder.getSingleton().getLoggerFactory(); // 获取 Log4jLoggerFactory 实例
2. 根据 ILoggerFactory
获取 Logger
实例
Log4jLoggerFactory
实现了 SLF4J 的 ILoggerFactory
接口,并负责根据名称返回 Logger
实例。具体步骤如下:
@Override
protected Logger newLogger(final String name, final LoggerContext context) {
final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name;
return new Log4jLogger(context.getLogger(key), name);
}
@Override
protected LoggerContext getContext() {
final Class<?> anchor = ReflectionUtil.getCallerClass(FQCN, PACKAGE);
return anchor == null ? LogManager.getContext() : getContext(ReflectionUtil.getCallerClass(anchor));
}
- 步骤 2.1:通过 Log4j 2 的
LoggerContext
获取Logger
实例,这与 Log4j 2 的原生方式一致。 - 步骤 2.2:将
org.apache.logging.log4j.core.Logger
封装成 SLF4J 的Logger
接口实现(即Log4jLogger
),从而实现 SLF4J 的日志调用。
3. 日志记录过程
当调用 SLF4J 的日志方法时(如 logger.debug()
),日志请求会被传递到 Log4jLogger
,并最终委托给 Log4j 2.x 的原生 Logger
实例进行处理。Log4j 2 会根据配置文件(如 log4j2.xml
)进行日志输出。
小结
- 依赖关系:通过
slf4j-api
、log4j-api
、log4j-core
和log4j-slf4j-impl
实现 SLF4J 与 Log4j 2.x 的集成。 - 核心过程:SLF4J 通过
StaticLoggerBinder
类绑定到 Log4j 2,Log4jLoggerFactory
创建Logger
实例,最终通过Log4jLogger
封装 Log4j 2 的Logger
。 - 日志调用转发:SLF4J 的日志调用会被转发到 Log4j 2 进行实际的日志记录,并根据
log4j2.xml
配置输出日志。