背景:
今天新⽣成⼀个springboot项⽬,然⽽启动⽇志,还有mybatis的详细⽇志⽆法打印出来,⾃写程序中打印的⽇志可以输出;⽹上找了很多资料,都没法解决问题;于是决定跟⼀下源码,弄清springboot⽇志相关的逻辑。环境配置:macbook; intellij idea community edition 2020.03 ; gradle 6.8.3 jdk1.8 ;gradle引⽤包如下:
dependencies {
compile \"com.alibaba:fastjson:1.2.75\" compile \"mysql:mysql-connector-java\"
//spring
compile(\"org.springframework.boot:spring-boot-starter\")
compile(\"org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4\") compile(\"org.springframework.boot:spring-boot-starter-web\") compile(\"org.springframework.boot:spring-boot-starter-actuator\")
//lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
//test
testCompile('org.springframework.boot:spring-boot-starter-test') testImplementation 'io.projectreactor:reactor-test'}
springboot 默认⽇志使⽤的是logback(引⼊spring-boot-starter包后,就⾃动引⼊了logback-core,logback-classic两个包,当然还有slf4j的包),当springboot启动时,org.springframework.boot.context.logging.LoggingApplicationListener,该类211⾏注册的监控事件会被ApplicationStartingEvent触发;如下代码所⽰,会调⽤onApplicationStartingEvent初始化loggingSystem,⽽使⽤哪个⽇志组件,就要看loggingSystem初始化的值了
@Override
public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event); }
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); }
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event); }
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) { onContextClosedEvent(); }
else if (event instanceof ApplicationFailedEvent) { onApplicationFailedEvent(); } }
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader()); this.loggingSystem.beforeInitialize(); }
如下图是org.springframework.boot.logging.LoggingSystem类⾥⾯get函数的内容:⾸先会从system.getProperty中获取className,新⽣成的项⽬,取到的这个值都为空,SYSTEM_PROPERTY是⼀个固定值,就是该类的名字;那么loggingSystem的值就是从SYSTEM_FACTORY.getLoggingSystem(classLoader);获取到的;接下来我们得看LoggingSystemFactory.fromSpringFactories.getLoggingSystem取的值是什么了;
public static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();
private static final LoggingSystemFactory SYSTEM_FACTORY = LoggingSystemFactory.fromSpringFactories();public static LoggingSystem get(ClassLoader classLoader) {
String loggingSystemClassName = System.getProperty(SYSTEM_PROPERTY); if (StringUtils.hasLength(loggingSystemClassName)) { if (NONE.equals(loggingSystemClassName)) { return new NoOpLoggingSystem();
}
return get(classLoader, loggingSystemClassName); }
LoggingSystem loggingSystem = SYSTEM_FACTORY.getLoggingSystem(classLoader); Assert.state(loggingSystem != null, \"No suitable logging system located\"); return loggingSystem; }
private static LoggingSystem get(ClassLoader classLoader, String loggingSystemClassName) { try {
Class> systemClass = ClassUtils.forName(loggingSystemClassName, classLoader); Constructor> constructor = systemClass.getDeclaredConstructor(ClassLoader.class); constructor.setAccessible(true);
return (LoggingSystem) constructor.newInstance(classLoader); }
catch (Exception ex) {
throw new IllegalStateException(ex); } }
LoggingSystemFactory是⼀个接⼝,它的实现类在spring-boot-start有4个,其中3个是在内部内类实
现,DelegatingLoggingSystemFactory(JavaLoggingSystem,Log4J2LoggingSystem,LogbackLoggingSystem,内部类实现)。上⾯SYSTEM_FACTORY的实现就是DelegatingLoggingSystemFactory这个类,如下代码中delegates的值为JavaLoggingSystem,Log4J2LoggingSystem,LogbackLoggingSystem;三个类具体的加载逻辑在
SpringFactoriesLoader.loadFactories函数中,最终返回的loggingSystem就是前⾯函数返回列表中的第⼀个;
SpringFactoriesLoader.loadFactories 才是决定springboot默认会使⽤哪个⽇志组件关键:该类是spring的核⼼组件类,在spring-core包中,org.springframework.core.io.support.SpringFactoriesLoader;loggingSystem的值=LogbackLoggingSystem
public interface LoggingSystemFactory { /**
* Return a logging system implementation or {@code null} if no logging system is * available.
* @param classLoader the class loader to use * @return a logging system */
LoggingSystem getLoggingSystem(ClassLoader classLoader); /**
* Return a {@link LoggingSystemFactory} backed by {@code spring.factories}. * @return a {@link LoggingSystemFactory} instance */
static LoggingSystemFactory fromSpringFactories() { return new DelegatingLoggingSystemFactory(
(classLoader) -> SpringFactoriesLoader.loadFactories(LoggingSystemFactory.class, classLoader)); } }
class DelegatingLoggingSystemFactory implements LoggingSystemFactory {
private final Function * Create a new {@link DelegatingLoggingSystemFactory} instance. * @param delegates a function that provides the delegates */ DelegatingLoggingSystemFactory(Function @Override public LoggingSystem getLoggingSystem(ClassLoader classLoader) { List for (LoggingSystemFactory delegate : delegates) { LoggingSystem loggingSystem = delegate.getLoggingSystem(classLoader); if (loggingSystem != null) { return loggingSystem; } } } return null; } } 总结:虽然springboot会加载JavaLoggingSystem,Log4J2LoggingSystem,LogbackLoggingSystem三个⽇志实现类,但在选择时,还是会使⽤LogbackLoggingSystem作为它的⽇志框架 到此这篇关于springboot默认⽇志框架选择源码解析的⽂章就介绍到这了,更多相关springboot⽇志框架内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持! 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- stra.cn 版权所有 赣ICP备2024042791号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务