這篇文章是《SpringBoot2.x入門》專輯的第6篇文章,使用的SpringBoot
版本爲2.3.1.RELEASE
,JDK
版本爲1.8
。java
這篇文章主要簡單聊聊鉤子接口CommandLineRunner
和ApplicationRunner
,下文有時候統稱二者爲Runner
。git
參考org.springframework.boot.SpringApplication#run()
方法的源碼,能夠知道CommandLineRunner
和ApplicationRunner
的回調時機:github
在全部的CommandLineRunner
和ApplicationRunner
回調以前,下面的步驟已經確保執行完畢:spring
Environment
內置變量的建立和屬性填充已經完成。Banner
已經打印完畢。ApplicationContext
和BeanFactory
建立完成,而且完成了上下文刷新(refreshContext
),意味着全部單例的Bean
完成了初始化以及屬性裝配。Servlet
容器啓動成功,如內置的Tomcat
、Jetty
容器已經正常啓動,能夠正常接收請求和處理。Started OrderExportApplication in XXX seconds (JVM running for YYY)
。也就是CommandLineRunner
或者ApplicationRunner
回調的時候,可使用全部上下文中存在的單例Bean
和Environment
內置變量中已經存在的屬性值,因此不少時候demo
項目都會在CommandLineRunner
或者ApplicationRunner
中進行操做。編程
CommandLineRunner
和ApplicationRunner
沒有本質區別,惟一的區別在:CommandLineRunner#run()
接收來自於main
方法的參數,類型是字符串數組(不定字符串數組),而ApplicationRunner#run()
接收ApplicationArguments
類型的參數,對應的實現類是DefaultApplicationArguments
。數組
能夠直接把註解@Component
應用在CommandLineRunner
或者ApplicationRunner
的實現類上,相對於把對應的實現單例添加到Spring
上下文中。例如:緩存
@Slf4j @Component public class CustomCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("CustomCommandLineRunner runs..."); } }
也能夠經過@Bean
註解,直接做用於CommandLineRunner
的匿名類對應的方法上,例如:ide
@Slf4j @Configuration public class CommandLineRunners { @Bean public CommandLineRunner commandLineRunner(){ return args -> log.info("CommandLineRunners commandLineRunner"); } }
或者直接在啓動類實現CommandLineRunner
接口(這種方式不推薦使用):spring-boot
@Slf4j @SpringBootApplication public class Ch5Application implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(Ch5Application.class, args); } @Override public void run(String... args) throws Exception { log.info("Ch5Application CommandLineRunner runs..."); } }
此外,能夠經過實現org.springframework.core.Ordered
接口或者@Order
註解定義Runner
回調的順序,指定的順序數越小,優先級越高。測試
這一小節是根據我的的編程習慣提出的建議。Runner
鉤子接口回調的時候若是拋出異常,會直接致使應用進程退出,因此若是在Runner
回調方法中必定要注意異常的捕獲和處理。基於這個特性,結合前面分析Runner
接口的回調時機,它適用的主要場景有:
@Profile
註解使用,指定特定的profile
才生效)。main
方法的入參。下面使用CommandLineRunner
啓動全部Quartz
中的Job
(記得先引入依賴spring-boot-starter-quartz
以及quartz
),爲了簡單起見調度器使用內存態:
@Slf4j @DisallowConcurrentExecution public class SimpleJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { log.info("SimpleJob run..."); } } @Component public class QuartzCommandLineRunner implements CommandLineRunner { @Autowired private Scheduler scheduler; @Override public void run(String... args) throws Exception { JobDetail job = JobBuilder.newJob(SimpleJob.class).storeDurably().withIdentity(JobKey.jobKey("SimpleJob")).build(); // 30秒執行一次 Trigger trigger = TriggerBuilder.newTrigger() .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(30)) .forJob(job).build(); scheduler.scheduleJob(job, trigger); } }
啓動應用後,日誌以下:
本文demo
項目倉庫:
(本文完 c-2-d e-a-20200712)
技術公衆號《Throwable文摘》(id:throwable-doge),不按期推送筆者原創技術文章(毫不抄襲或者轉載):