private void refreshContext(ConfigurableApplicationContext context) { // 由于这里需要调用父类一系列的refresh操作,涉及到了很多核心操作,因此耗时会比较长,本文不做具体展开 refresh(context); // 注册一个关闭容器时的钩子函数 if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } } // 调用父类的refresh方法完成容器刷新的基础操作 protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext)applicationContext).refresh(); }
注册关闭容器时的钩子函数的默认实现是在 AbstractApplicationContext 类中:
public void registerShutdownHook() { if(this.shutdownHook == null) { this.shutdownHook = new Thread() { public void run() { synchronized(AbstractApplicationContext.this.startupShutdownMonitor) { AbstractApplicationContext.this.doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); } }
如果没有提供自定义的shutdownHook,那么会生成一个默认的,并添加到Runtime中。默认行为就是调用它的doClose方法,完成一些容器销毁时的清理工作。
3.2.6 Spring Context后置处理
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { callRunners(context, args); } private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<Object>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<Object>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } } private void callRunner(ApplicationRunner runner, ApplicationArguments args) { try { (runner).run(args); } catch (Exception ex) { throw new IllegalStateException("Failed to execute ApplicationRunner", ex); } } private void callRunner(CommandLineRunner runner, ApplicationArguments args) { try { (runner).run(args.getSourceArgs()); } catch (Exception ex) { throw new IllegalStateException("Failed to execute CommandLineRunner", ex); } }
所谓的后置操作,就是在容器完成刷新后,依次调用注册的Runners。Runners可以是两个接口的实现类:
- org.springframework.boot.ApplicationRunner
- org.springframework.boot.CommandLineRunner
CommandLineRunner、ApplicationRunner 接口是在容器启动成功后的最后一步回调(类似开机自启动)
这两个接口有什么区别呢:
public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; } public interface CommandLineRunner { void run(String... args) throws Exception; }
其实没有什么不同之处,除了接口中的run方法接受的参数类型是不一样的以外。一个是封装好的 ApplicationArguments 类型,另一个是直接的String不定长数组类型。因此根据需要选择相应的接口实现即可。
作者:徐志毅
链接:https://www.jianshu.com/p/dc12081b3598
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。