前提

这篇文章是《SpringBoot2.x入门》专辑的第6篇文章,使用的SpringBoot版本为2.3.1.RELEASEJDK版本为1.8

这篇文章主要简单聊聊钩子接口CommandLineRunnerApplicationRunner,下文有时候统称两者为Runner

Runner的回调时机

参考org.springframework.boot.SpringApplication#run()方法的源码,可以知道CommandLineRunnerApplicationRunner的回调时机:

在所有的CommandLineRunnerApplicationRunner回调之前,下面的步骤已经确保执行完毕:

  1. Environment内置变量的创建和属性填充已经完成。
  2. Banner已经打印完毕。
  3. ApplicationContextBeanFactory创建完成,并且完成了上下文刷新(refreshContext),意味着所有单例的Bean完成了初始化以及属性装配。
  4. Servlet容器启动成功,如内置的TomcatJetty容器已经正常启动,可以正常接收请求和处理。
  5. 启动信息完成打印,一般会看到日志输出类似Started OrderExportApplication in XXX seconds (JVM running for YYY)

也就是CommandLineRunner或者ApplicationRunner回调的时候,可以使用所有上下文中存在的单例BeanEnvironment内置变量中已经存在的属性值,所以很多时候demo项目都会在CommandLineRunner或者ApplicationRunner中进行操作。

Runner的简单使用

CommandLineRunnerApplicationRunner没有本质区别,唯一的区别在: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的匿名类对应的方法上,例如:

@Slf4j
@Configuration
public class CommandLineRunners { @Bean
public CommandLineRunner commandLineRunner(){
return args -> log.info("CommandLineRunners commandLineRunner");
}
}

或者直接在启动类实现CommandLineRunner接口(这种方式不推荐使用):

@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回调方法中一定要注意异常的捕获和处理。基于这个特性,结合前面分析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),不定期推送笔者原创技术文章(绝不抄袭或者转载):

SpringBoot2.x入门:使用CommandLineRunner钩子接口的更多相关文章

  1. SpringBoot2.x入门教程:理解配置文件

    前提 这篇文章是<SpringBoot2.x入门>专辑的第4篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 主要介绍SpringBoot配置文件一 ...

  2. SpringBoot2.x入门教程:引入jdbc模块与JdbcTemplate简单使用

    这是公众号<Throwable文摘>发布的第23篇原创文章,收录于专辑<SpringBoot2.x入门>. 前提 这篇文章是<SpringBoot2.x入门>专辑的 ...

  3. SpringBoot2.x入门:使用MyBatis

    这是公众号<Throwable文摘>发布的第25篇原创文章,收录于专辑<SpringBoot2.x入门>. 前提 这篇文章是<SpringBoot2.x入门>专辑的 ...

  4. SpringBoot2.x入门:快速创建一个SpringBoot应用

    前提 这篇文章是<SpringBoot2.x入门>专辑的第2篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 常规的套路会建议使用Spring官方提 ...

  5. SpringBoot2.x入门:引入web模块

    前提 这篇文章是<SpringBoot2.x入门>专辑的第3篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 主要介绍SpringBoot的web模 ...

  6. Springboot2.x入门——helloWorld

    Springboot2.x入门--helloWorld 一.简介 1.1 Springboot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的 ...

  7. MyBatis基础入门《四》接口方式.Select查询集合

    MyBatis基础入门<四>接口方式.Select查询集合 描述: 在<MyBatis基础入门<二>Select查询>中有说过,SQLSession有两种用法,这里 ...

  8. Spring(七)核心容器 - 钩子接口

    目录 前言 1.Aware 系列接口 2.InitializingBean 3.BeanPostProcessor 4.BeanFactoryPostProcessor 5.ImportSelecto ...

  9. SpringBoot2.x入门:应用打包与启动

    前提 这篇文章是<SpringBoot2.x入门>专辑的第5篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 这篇文章分析一个偏向于运维方面的内容: ...

随机推荐

  1. c常用函数-sprintf

    sprintf sprinti函数的作用是把一个字符串格式化后输入到另一个字符串中,然后返回写入的·字符数量. Sprinf在用法上和1.2.3节的prinf函数一致,区别是sprintf输出结果到指 ...

  2. 成为python程序员,对疫情过后的毕业生来说,真是一个不错的方向吗?

    Python最近几年,一直被炒得很火,这其中有商业因素,但更重要的是即将到来的人工智能时代,而python就恰好是最适合的编程语言. 所以无论是在职的人,还是在校的学生,都想着跟上这一趋势,但,在今年 ...

  3. 从零开始学习Prometheus监控报警系统

    Prometheus简介 Prometheus是一个开源的监控报警系统,它最初由SoundCloud开发. 2016年,Prometheus被纳入了由谷歌发起的Linux基金会旗下的云原生基金会( C ...

  4. JAVA相关基础知识

    JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分, ...

  5. InnoDB 中 B+ 树索引的分裂

    数据库中B+树索引的分裂并不总是从页的中间记录开始,这样可能会导致空间的浪费,例如下面的记录: 1, 2, 3, 4, 5, 6, 7, 8, 9 插入式根据自增顺序进行的,若这时插入10这条记录后需 ...

  6. JavaScript 集合基本操作

    参考 MDN 集合 Array 1. 2种创建数组的方式 var fruits = [] ; var friuits = new Array(); 2. 遍历 fruits.forEach(funct ...

  7. weblogic高级进阶之查看日志

    域的日志位于 D:\Oracle\Middleware\user_projects\domains\base_domain\servers\AdminServer\logs 名字是base_domai ...

  8. android自定义控件onLayout方法

    onLayout设置子控件的位置,对应一些普通的控件例如Button.TextView等控件,不存在子控件,所以可以不用复写该方法. 向线性布局.相对布局等存在子控件,可以覆写该方法去控制子控件的位置 ...

  9. cookie,session,jwt,token,oauth2联系和区别

    为啥有这么多的东西? 由于互联网在刚开始设计的时候是展现静态网页为主,没有现在这么多的交互和互动,所以被设计为了无状态,随用随走的简单模式.随着互联网的发展,各种具有和用户交互功能的网站出现,要求用户 ...

  10. 入门大数据---Map/Reduce,Yarn是什么?

    简单概括:Map/Reduce是分布式离线处理的一个框架. Yarn是Map/Reduce中的一个资源管理器. 一.图形说明下Map/Reduce结构: 官方示意图: 另外还可以参考这个: 流程介绍: ...