Spring Boot自动运行之 CommandLineRunner、ApplicationRunner和@PostConstruct
在使用Spring Boot开发的工作中,我们经常会需要遇到一种功能需求,比如在服务启动时候,去加载一些配置,去请求一下其他服务的接口。Spring Boot给我们提供了三种常用的实现方法:
第一种是实现CommandLineRunner接口,
第二种是实现ApplicationRunner接口
第三种是使用注解:@PostConstruct
1、CommandLineRunner
1、CommandLineRunner执行的时间节点是在Application完成初始化工作之后。
2、CommandLineRunner在有多个实现的时候,可以使用@order注解指定执行先后顺序。
3、源码在:org.springframework.boot.SpringApplication#run(),可以看看
我们先看一下CommandLineRunner的源码:
package org.springframework.boot;
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
SpringApplication源码:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
callRunners方法源码:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
Iterator var4 = (new LinkedHashSet(runners)).iterator();
while(var4.hasNext()) {
Object runner = var4.next();
if (runner instanceof ApplicationRunner) {
this.callRunner((ApplicationRunner)runner, args);
}
if (runner instanceof CommandLineRunner) {
this.callRunner((CommandLineRunner)runner, args);
}
}
}
我们写一个例子实现:
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
@Order(1)
public class CommandLineRunnerTest implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("----CommandLineRunnerTest1 start---"+ Arrays.toString(args));
}
}
2、ApplicationRunner
ApplicationRunner跟CommandLineRunner是区别是在run方法里接收的参数不同,CommandLineRuner接收的参数是String... args,而ApplicationRunner的run方法的参数是ApplicationArguments
看看ApplicationRunner的源码:
package org.springframework.boot;
@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
我们写一个例子实现:
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
@Component
@Order(1)
public class ApplicationRunnerTest implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("---ApplicationRunnerTest start----");
List<String> nonOptionArgs = args.getNonOptionArgs();
System.out.println("[非选项参数]>>> " + nonOptionArgs);
Set<String> optionNames = args.getOptionNames();
for(String optionName: optionNames) {
System.out.println("[选项参数]>>> name:" + optionName
+ ";value:" + args.getOptionValues(optionName));
}
}
}
3、@PostConstruct
@PostConstruct是在javaEE5的时候引入的,它并不是Spring提供的,但是Spring有对@PostConstruct的实现。并且是在对象加载完之后执行。
先看注解源码
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
我们写一个例子实现:
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class PostConstructTest {
@PostConstruct
public void start(){
System.out.println("---PostConstruct start---");
}
}
运行代码输出结果 :

5、源码
https://gitee.com/Qinux/command-line-runner-demo.git
微信公众号:一凡码农
欢迎交流
Spring Boot自动运行之 CommandLineRunner、ApplicationRunner和@PostConstruct的更多相关文章
- Spring Boot自动配置与Spring 条件化配置
SpringBoot自动配置 SpringBoot的自动配置是一个运行时(应用程序启动时)的过程,简化开发时间,无需浪费时间讨论具体的Spring配置,只需考虑如何利用SpringBoot的自动配置即 ...
- Spring Boot自动配置原理、实战
Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...
- Spring Boot自动配置
Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...
- Spring boot 自动配置自定义配置文件
示例如下: 1. 新建 Maven 项目 properties 2. pom.xml <project xmlns="http://maven.apache.org/POM/4 ...
- Spring Boot 自动装配(二)
目录 目录 前言 1.起源 2.Spring Boot 自动装配实现 2.1.@EnableAutoConfiguration 实现 2.1.1. 获取默认包扫描路径 2.1.2.获取自动装配的组件 ...
- Spring Boot自动配置原理(转)
第3章 Spring Boot自动配置原理 3.1 SpringBoot的核心组件模块 首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量: 我们cd到spring-boot- ...
- Spring Boot自动配置如何工作
通过使用Mongo和MySQL DB实现的示例,深入了解Spring Boot的@Conditional注释世界. 在我以前的文章“为什么选择Spring Boot?”中,我们讨论了如何创建Sprin ...
- Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...
- Spring Boot 自动配置之@Conditional的使用
Spring Boot自动配置的"魔法"是如何实现的? 转自-https://sylvanassun.github.io/2018/01/08/2018-01-08-spring_ ...
- 将Spring Boot项目运行在Docker上
将Spring Boot项目运行在Docker上 一.使用Dockerfile构建Docker镜像 1.1Dockerfile常用指令 1.1.1ADD复制文件 1.1.2ARG设置构建参数 1.1. ...
随机推荐
- 在QEMU-KVM环境下部署Oracle 19.16 RAC
KVM环境和其他虚拟化或真实生产最大差异主要就是在实施前期准备工作上: 具体在 DB节点 和存储环境 的准备工作上有差异,本文会详细说明. 而剩余基本软件安装和补丁应用部分无差异,若不清楚可以直接参考 ...
- 小知识:如何判定crontab任务的执行频度
所有运维人员都知道crontab定时任务的基本格式如下: * * * * * command 分 时 日 月 周 命令或脚本 如果是写了具体的时间,基本大家都可以清楚的根据这样的规则去匹配对应: 第1 ...
- Spring 与 Mybatis 中的 @Repository 与 @Mapper
@Repository.@Service.@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean.如果使用@Repository则需要使用@MapperScan(&quo ...
- 【Unity3D】UGUI回调函数
1 简述 UGUI 回调函数主要指鼠标进入.离开.点下.点击中.抬起.开始拖拽.拖拽中.拖拽结束 UI 控件触发的回调.使用 UGUI 回调函数时,需要引入 UnityEngine.EventSy ...
- 【framework】DisplayContent简介
1 前言 DisplayContent 用于管理屏幕,一块屏幕对应一个 DisplayContent 对象,虽然手机只有一个显示屏,但是可以创建多个 DisplayContent 对象,如投屏时, ...
- Windows SDK 之 mciSendString最后一个参数
这里在这里先附上mciSendString的函数原型: MCIERROR mciSendString( LPCTSTR lpszCommand, LPTSTR lpszReturnString, UI ...
- Linux crontab不执行
Linux 系统里面计划任务,crontab 没有如期执行这是运维工作中比较常见的一种故障了. 下面结合最近部署自动脚本不执行问题排查步骤: 1.检查 crontab 服务是否正常 [dmdba@te ...
- win32 - 富文本控件的文本突出显示和文本撤销
#define UNICODE #define _UNICODE #include <tchar.h> #include <windows.h> #include <wi ...
- 公司官网建站笔记(二):在云服务器部署PHP服务(公网访问首页)
前言 上一篇重新安装了CentOS8.2之后,接下来开始安装部署PHP服务器,让公网可以访问到我们部署的PHP服务器首页. 背景 为什么自行搭建,是因为红胖子专业做相关Qt软件以及终端设备 ...
- django中的Case,When,then用法
# 参考文档 https://docs.djangoproject.com/en/2.2/ref/models/conditional-expressions/ # Case()接受任意数量的When ...