Spring5 日志使用 Spring-jcl 模块。
测试一下spring5 的默认日志实现:
public class LogDemo {
public static void main(String[] args) {
Log logger = LogFactory.getLog(LogDemo.class);
logger.info("Spring 5 默认日志框架 - " + logger.getClass().getName());
}
}
输出如下:
信息: Spring 5 默认日志框架 - org.apache.commons.logging.LogAdapter$JavaUtilLog
默认是用java.util.logging 框架。
从spring的源码也可看出:
进一步查看LogFactory.getLog源码
/**
* Convenience method to return a named logger.
* @param clazz containing Class from which a log name will be derived
*/
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}
/**
* Convenience method to return a named logger.
* @param name logical name of the <code>Log</code> instance to be returned
*/
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
继续查看:LogAdapter.createLog
/**
* Create an actual {@link Log} instance for the selected API.
* @param name the logger name
*/
public static Log createLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jAdapter.createLog(name);
case SLF4J_LAL:
return Slf4jAdapter.createLocationAwareLog(name);
case SLF4J:
return Slf4jAdapter.createLog(name);
default:
// Defensively use lazy-initializing adapter class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
return JavaUtilAdapter.createLog(name);
}
}
这里会进入默认分支,执行 JavaUtilAdapter.createLog(name);
内部类:
private static class JavaUtilAdapter {
public static Log createLog(String name) {
return new JavaUtilLog(name);
}
}
继续实例化内部类JavaUtilLog
private static class JavaUtilLog implements Log, Serializable {
private String name;
private transient java.util.logging.Logger logger;
public JavaUtilLog(String name) {
this.name = name;
this.logger = java.util.logging.Logger.getLogger(name);
}
@Override
public boolean isFatalEnabled() {
return isErrorEnabled();
}
this.logger = java.util.logging.Logger.getLogger(name); 可以看到使用了java.util.logging框架。
如何集成第三方日志框架?
/**
* Spring's common JCL adapter behind {@link LogFactory} and {@link LogFactoryService}.
* Detects the presence of Log4j 2.x / SLF4J, falling back to {@code java.util.logging}.
*
* @author Juergen Hoeller
* @since 5.1
*/
final class LogAdapter {
private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger";
private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider";
private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger";
private static final String SLF4J_API = "org.slf4j.Logger";
检测Log4j 2.x / SLF4J,否则使用java.util.logging
集成Log4j2:
第一步:maven添加log4j2.x依赖
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
第二步:配置log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
测试:
public class LogDemo {
public static void main(String[] args) {
Log logger = LogFactory.getLog(LogDemo.class);
logger.info("Spring 5 日志框架 - " + logger.getClass().getName());
}
}
输入如下:
11:57:09.871 [main] INFO org.xharvard.log.LogDemo - Spring 5 日志框架 - org.apache.commons.logging.LogAdapter$Log4jLog