这篇文章是《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),不按期推送笔者原创技术文章(毫不抄袭或者转载):