一、前言

  • 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(三)的更多相关文章

  1. springboot源码解析-管中窥豹系列

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  2. springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  3. springboot源码解析-管中窥豹系列之BeanPostProcessor(十二)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  4. springboot源码解析-管中窥豹系列之bean如何生成?(十四)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  5. springboot源码解析-管中窥豹系列之web服务器(七)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  6. springboot源码解析-管中窥豹系列之BeanDefinition(八)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  7. springboot源码解析-管中窥豹系列之自动装配(九)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  8. springboot源码解析-管中窥豹系列之EnableXXX(十)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  9. springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

随机推荐

  1. js- 判断属性是否 属于该对象 hasOwnProperty()

    var obj ={ name:'suan', sex :'male', age:150, height:185, characeter:true, _proto_:{ lastName:'susan ...

  2. APIO2020 粉刷墙壁

    考场想了 5.5 h,第一部分分死活打不出来,做到崩盘,现在重做,感觉自己就是一个sb,放学在地铁上一眼就会了.哎. 可以把一个要求看作一个长度为 \(m\) 的区间:\([l, l + m - 1] ...

  3. Social Infrastructure Information Systems Division, Hitachi Programming Contest 2020 D题题解

    将题意转换为一开始\(t = 0\),第\(i\)个操作是令\(t \leftarrow (a_i + 1) t + (a_i + b_i + 1)\).记\(A_i = a_i + 1, B_i = ...

  4. Codeforces Edu Round 48 A-D

    A. Death Note 简单模拟,可用\(\%\)和 \(/\)来减少代码量 #include <iostream> #include <cstdio> using nam ...

  5. tcp/ip原理/三次握手/四次挥手

    @ tcp/ip原理 1.1 tcp/ip三次握手 1.1.1 建立过程说明 a)   由主机A发送建立TCP连接的请求报文, 其中报文中包含seq序列号, 是由发送端随机生成的, 并且还将报文中SY ...

  6. MISC-吹着贝斯扫二维码

    题目 [安洵杯 2019]吹着贝斯扫二维码 解压附件,有36个文件和一个压缩包,压缩包带密码和备注 分析 文件类型 随便打开一个不明文件,是jpg图片啊(FF D8 FF) 改一个试试,有一个小块二维 ...

  7. ARM开发工具下载地址汇总

    一,下载地址 1,ARM DS5官方下载地址https://developer.arm.com/tools-and-software/embedded/legacy-tools/ds-5-develo ...

  8. Flink读取resource资源文件

    public static ParameterTool getParameterTool(String[] args){ try { return ParameterTool .fromPropert ...

  9. jquery ajax return不起作用

    jquery的ajax方法:在success中使用return:来结束程序的时候,结束的只是success这个方法,也就是说success中的return的作用范围只是success: 如果要想在su ...

  10. asp.net webapi 给字段赋初始值DefaultValue 解决前端传空字符串后台接受不是“”而是NULL

    /// <summary> /// 存储ID /// </summary> public Guid SaveID { get; set; } /// <summary&g ...