spring-boot使用logback的坑2

接上篇说道spring-boot在使用logback的坑之后又发现一个坑,自定义的appender以及原生的appender的stop()方法不会调用,导致部分清理工作无法完成。
原因:上篇说到去掉了LoggingApplicationListener使spring-boot不再管理logback,导致没有add一个shutdownhook
首先我们去掉上篇的方法,让spring-boot依旧管理logback,这样理论上就可以调用stop做清理工作了,但是最后发现还是不行,debug跟踪代码,如下:
private void registerShutdownHookIfNecessary(Environment environment,
      LoggingSystem loggingSystem) {
   boolean registerShutdownHook = new RelaxedPropertyResolver(environment)
         .getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTYBoolean.class, false);
   if (registerShutdownHook) {
      Runnable shutdownHandler = loggingSystem.getShutdownHandler();
      if (shutdownHandler != null
            && shutdownHookRegistered.compareAndSet(false, true)) {
         registerShutdownHook(new Thread(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
public Runnable getShutdownHandler() {
   return new ShutdownHandler();
}


private final class ShutdownHandler implements Runnable {

   @Override
   public void run() {
      getLoggerContext().stop();
   }

}

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

private LoggerContext getLoggerContext() {
   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 = new DelayingShutdownHook();
Runtime.getRuntime().addShutdownHook(new Thread(shutdownHook));

启动,果真ok~~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值