spring-boot使用logback的坑2

2022-11-21 10:25:13
接上篇说道spring-boot在使用logback的坑之后又发现一个坑,自定义的appender以及原生的appender的stop()方法不会调用,导致部分清理工作无法完成。
原因:上篇说到去掉了LoggingApplicationListener使spring-boot不再管理logback,导致没有add一个shutdownhook
首先我们去掉上篇的方法,让spring-boot依旧管理logback,这样理论上就可以调用stop做清理工作了,但是最后发现还是不行,debug跟踪代码,如下:
private voidregisterShutdownHookIfNecessary(Environment environment,
LoggingSystem loggingSystem) {
booleanregisterShutdownHook =newRelaxedPropertyResolver(environment)
         .getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY,Boolean.class, false);
   if(registerShutdownHook) {
      Runnable shutdownHandler = loggingSystem.getShutdownHandler();
      if(shutdownHandler !=null
&&shutdownHookRegistered.compareAndSet(false, true)) {
         registerShutdownHook(newThread(shutdownHandler));
}
   }
}
registerShutdownHook这个变量的值默认是false,所以不会加hook,查看REGISTER_SHUTDOWN_HOOK_PROPERTY,发现该值为:logging.register-shutdown-hook,那么这个应该是spring-boot中的application.properties中的配置项,将该值配置为true
结果发现果真可以调用stop。
那么这样又会引入之前上篇说到的初始化两次的问题,其实spring-boot在logback初始化之后会reset一次,自己再重新初始化,对程序没有影响,但是自定义的appender的log会打印两次,总是觉得不舒服。所以该问题应该从logback入手,让logback加一个hook去做清理工作
我们模仿spring-boot中的方法,看它如何实现,上面代码第6行调用getShutdownHandler(),我们进入该方法,LogbackLoggingSystem中:

@Override
publicRunnablegetShutdownHandler() {
return newShutdownHandler();
}


private final classShutdownHandlerimplementsRunnable {

@Override
public voidrun() {
      getLoggerContext().stop();
}

}

一直到现在的代码还是包在spring-boot中,我们不想引入spring的包,所以继续往下看,

privateLoggerContextgetLoggerContext() {
   ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
Assert.isInstanceOf(LoggerContext.class,factory,
String.format(
"LoggerFactory is not a Logback LoggerContext but Logback is on "
+"the classpath. Either remove Logback or the competing "
+"implementation (%s loaded from %s). If you are using "
+"WebLogic you will need to add 'org.slf4j' to "
+"prefer-application-packages in WEB-INF/weblogic.xml",
factory.getClass(),getLocation(factory)));
   return(LoggerContext) factory;
}

终于LoggerContext是logback中的类,我们只要拿到这个context,然后调用它的stop方法就可以了。
偶然发现logback-core包中有一个hook的package,那么更简单了,直接注册这个hook里面的某个类应该更简单,那么可以在自定义的appender中的start方法加入如下代码:

DelayingShutdownHook shutdownHook =newDelayingShutdownHook();
Runtime.getRuntime().addShutdownHook(newThread(shutdownHook));

启动,果真ok~~
  • 作者:Cumu_
  • 原文链接:https://jthink.blog.csdn.net/article/details/52613953
    更新时间:2022-11-21 10:25:13