在实际项目中,咱们须要在springboot服务启动后作一些初始化工做,例如线程池初始化、文件资源加载、常驻后台任务启动(好比kafka consumer)等。本文介绍3类初始化资源的方法:html
ApplicationRunner
与CommandLineRunner
接口Spring 容器中的 Bean 是有生命周期的,Spring 容许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操做,经常使用的设定方式有如下三种:java
执行的前后顺序:构造方法 --> @PostConstruct
注解的方法 --> afterPropertiesSet
方法(InitializingBean
接口) --> init-method
指定的方法。详情参考Spring Bean 初始化之InitializingBean, init-method 和 PostConstructgit
CommandLineRunner
/ApplicationRunner
接口的 Component
会在全部 Spring Beans
都初始化以后,SpringApplication.run()
以前执行,很是适合在应用程序启动之初进行一些数据初始化的工做。CommandLineRunner
和ApplicationRunner
这两个接口工做方式相同,都只提供单一的run方法,惟一的区别是run方法的入参类型不一样,CommandLineRunner
的参数是最原始的参数,没有进行任何处理,ApplicationRunner
的参数是ApplicationArguments
,是对原始参数的进一步封装。github
如下定义了两个runner,其中Order
注解指定了执行顺序,数字越小越先执行web
@Order(1) @Component @Slf4j public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) { log.info("MyCommandLineRunner run..."); } } ------------------------------------------------------------------- @Order(2) @Component @Slf4j public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { log.info("MyApplicationRunner run..."); } }
跟踪源码,看下CommandLineRunner
/ApplicationRunner
是如何被调用的,Springboot在启动的时候,都会构造一个SpringApplication
实例,执行run方法,一路点进去后不难发现调用入口是SpringApplication.run
方法中的callRunners(context, applicationArguments)
spring
public ConfigurableApplicationContext run(String... args) { ...... listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, listeners, exceptionReporters, ex); throw new IllegalStateException(ex); } listeners.running(context); return context; }
callRunners()
能够看出是run方法内部最后一个调用的方法(能够认为是main方法执行完成以前最后一步)Spring的事件机制其实是设计模式中观察者模式的典型应用。观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态改变时,须要通知相应的观察者,使这些观察者可以自动更新。segmentfault
Spring的事件驱动模型由三部分组成设计模式
ApplicationEvent
,继承自JDK的EventObject
,全部事件都要继承它,也就是被观察者ApplicationEventPublisher
及ApplicationEventMulticaster
接口,使用这个接口,就能够发布事件了ApplicationListener
,继承JDK的EventListener
,全部监听者都继承它,也就是咱们所说的观察者,固然咱们也可使用注解 @EventListener
,效果是同样的在Spring框架中,内置了4种事件:springboot
以ContextRefreshedEvent
为例,建立一个listener很是简单app
@Component @Slf4j public class MyContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { log.info("ContextRefreshedEvent listen... "); } }
MyContextRefreshListener
监听了内置事件ContextRefreshedEvent
,即容器初始化完成后调用,MyContextRefreshListener.onApplicationEvent
会被调用,利用此特性能够作一些初始化工做
注意: 在传统的基于XML配置的Spring项目中会存在二次调用的问题,即调用两次该方法,缘由是在传统的Spring MVC项目中,系统存在两个容器,一个root容器,一个project-servlet.xml对应的子容器,在初始化这两个容器的时候都会调用该方法一次,因此有二次调用的问题,而对于基于Springboot的项目不存在这个问题
方法1(spring bean初始化) --> spring事件ContextRefreshedEvent
--> CommandLineRunner/ApplicationRunner,示例代码下载请戳代码下载地址