springboot源码解析-管中窥豹系列之Runner(三)
一、前言
- Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。
- 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

二、Runner
- 假如我们想在springboot项目启动完成之后,做点什么,我们应该怎么办呢?
- 注意我们可以写在bean的初始化方法里面(我们后面讲),但是我们要用到其它已经加载了的bean的能力,又怎么办呢?
- 当然加顺序,加依赖也能解决,就是麻烦
这一节我们讨论一下springboot项目的Runner,Runner是在spring加载完毕执行的,springboot有两种Runner:
- ApplicationRunner
- CommandLineRunner
@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
- 两种除了参数不同,其它没区别
- ApplicationArguments是对传参数组的封装,本质也没区别
- 只有执行顺序上有区别,下面源码会看到
三、用法
实现接口就可以了
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class HelloRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("hello runner");
}
}
- 因为这时候spring已经加载完毕,你可以引入其它bean
- 启动项目,你会发现在日志最下方打印了上面的话
四、源码解读
我们直接找SpringApplication类的run方法,想看整体框架的去第一节。
public ConfigurableApplicationContext run(String... args) {
...
try {
...
callRunners(context, applicationArguments);
...
}
catch (Throwable ex) {
...
}
...
return context;
}
我们直接定位到callRunners方法。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// (1) 找到ApplicationRunner的实现类,加到list里面
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// (2) 找到CommandLineRunner的实现类,加到list里面
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// (3) 排序
AnnotationAwareOrderComparator.sort(runners);
// (4) 钩子回调
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
总共分四步:
(1) 找到ApplicationRunner的实现类,加到list里面
(2) 找到CommandLineRunner的实现类,加到list里面
(3) 排序
(4) 钩子回调
我们看一下canllRunner
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}
- 除了传参方式,都一样。
- 上面说的执行顺序问题,是先添加的ApplicationRunner,如果只有@Component,先执行ApplicationRunner
欢迎关注公众号:丰极,更多技术学习分享。
springboot源码解析-管中窥豹系列之Runner(三)的更多相关文章
- springboot源码解析-管中窥豹系列
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之BeanPostProcessor(十二)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之bean如何生成?(十四)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之web服务器(七)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之BeanDefinition(八)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之自动装配(九)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之EnableXXX(十)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
随机推荐
- Hbase的基本原理(与HIVE的区别、数据结构模型、拓扑结构、水平分区原理、场景)
重点:HBase的基本数据模型.拓扑结构.部署配置方法,并介绍通过命令行和编程方式使用HBase的基本方法. HBase:一种列存储模式与键值对相结合的NoSQL软件,但更多的是使用列存储模式,底层的 ...
- .NET 开源导入导出库 Magicodes.IE 2.5发布
今天我们发布了2.5版本,这当然也离不开大家对Magicodes.IE的支持,今天我也是跟往常一样列举了该版本一些重要的更新内容. 当然也要说一下,在这个版本中我们设计了全新的LOGO Excel导出 ...
- js实现跳转的几种方式
1. window.open("url"); 2.用自定义函数 <script> function openWin(tag,obj) { obj.target=&quo ...
- clion2020最新安装破解版教程 内含激活码、破解补丁、无限重置时间插件
clion是一款开发C.C++等相关程序的利器,到目前为止已经更新到2020.3版本啦!还没有升级的小伙伴们赶紧升级啦,本文教大家如何安装clion2020.3版本并且破解,此方法亲测100%可以永久 ...
- 题解 洛谷P6853 station
蒟蒻语 还是蒟蒻太菜了,这场 div1 竟然一题都没做出来/kk/kk/kk 蒟蒻解 首先我们把每 5 个点分为一组.然后分组结果大概是这样子: 可以看到首先下面需要有一条边来让整张图有一条支撑的路径 ...
- Python迭代器&生成器&装饰器
1. 迭代器 1.1 可迭代对象(Iterator) 迭代器协议:某对象必须提供一个__next__()方法,执行方法要么返回迭代中的下一项,要么引起一个Stopiteration异常,以终止迭代(只 ...
- 三、TestNG的基本注解(1)
Before类别和After类别注解 举例说明 创建两个TestNGAnnotationTest.java和TestNGAnnotationTest2.java的类 TestNGAnnotationT ...
- Docker修改默认的网段
一,问题 docker安装后默认的网段是172.17网段的,和真实环境网段冲突导致本机电脑无法连接docker机器. 二,解决办法 修改docker默认网段 1,先把docker停止 systemct ...
- 01-flask-helloWorld
代码 from flask import Flask # 创建Flask对象 app = Flask(__name__) # 定义路由 @app.route('/') def index(): # 函 ...
- css 17-CSS3的常见边框汇总
17-CSS3的常见边框汇总 #CSS3 常见边框汇总 <!DOCTYPE html> <html lang="en"> <head> < ...