背景:日常开发使用的是spring-boot框架,日志配置方式基本都是各个仓库相互copy的配置,究其为何如此配置不知原因,大多数都是尝试操作。
问题list:
日志整体理解很难,阐述一下要求证的问题,明确一下学习的边界。
1.spring-boot-starter-logging里使用的是什么日志,是如何生效的。
2.spring-boot 项目里如何配置logging
3.常见的日志框架或者api之间的关系:spring-boot-starter-logging, java.util.logging, slf4j, org.apache.commons.logging,logback, log4j,log4j2,slf4j2
4.lombok里的和日志相关的注解代表什么?和对应的日志框架是如何配置使用的。
5.以其中一个log框架为例,梳理其和spring-boot 和lombok的组合使用方式.
学习过程:
1. spring-boot-starter-logging.jar 基本解释
我们发现spring-boot-starter-logging.jar里只有 META-INF/MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: Spring Boot Logging Starter
Automatic-Module-Name: spring.boot.starter.logging
Implementation-Version: 2.1.3.RELEASE
Built-By: Spring
Created-By: Apache Maven 3.6.0
Build-Jdk: 1.8.0_202
以及对应的pom依赖:
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
</dependencies>
关于spring-boot-starter-*格式:https://juejin.im/post/5d9f41eae51d4578034d2db2
针对于spring-boot-starter-logging 总结起来就是:
(1)pom 文件里引入了相关依赖(具体的第三方实现);
(2) MANIFEST.MF Automatic-Module-Name 指定了logging入口相关的在 spring-boot-autoconfigure.jar包org.springframework.boot.autoconfigure下对应的目录(logging)
(3) spring-boot-autoconfigure/META-INF/spring.factories中声明了logging starter的入口类
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
2.spring-boot-logging-starter 代码分析
类:org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
LogFactory,LogAdapter都是spring-jcl里内容
public class ConditionEvaluationReportLoggingListener implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private final Log logger = LogFactory.getLog(getClass());
/** */
}
public abstract class LogFactory {
/** */
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}
/** */
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
/***/
}
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";
private static final LogApi logApi;
static {
if (isPresent(LOG4J_SPI)) {
if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) {
// log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI;
// however, we still prefer Log4j over the plain SLF4J API since
// the latter does not have location awareness support.
logApi = LogApi.SLF4J_LAL;
}
else {
// Use Log4j 2.x directly, including location awareness support
logApi = LogApi.LOG4J;
}
}
else if (isPresent(SLF4J_SPI)) {
// Full SLF4J SPI including location awareness support
logApi = LogApi.SLF4J_LAL;
}
else if (isPresent(SLF4J_API)) {
// Minimal SLF4J API without location awareness support
logApi = LogApi.SLF4J;
}
else {
// java.util.logging as default
logApi = LogApi.JUL;
}
}
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:
return JavaUtilAdapter.createLog(name);
}
}
/**/
}
到这一步基本搞懂了spring-boot-starter-logging是怎么处理日志的?
1. 日志的入口在autoconfigure
2.autoconfigure 里和日志相关的依赖
3.spring-jcl自己包了一层,支持slf4j 系列 ,log4j 系列,java原生日志记录
4.spring-boot-starter-logging 日志引入了相关的日志实现。
http://www.slf4j.org/images/legacy.png
这个图没理解,待看