在實際項目中,咱們須要在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,示例代碼下載請戳代碼下載地址