springboot源码解析-管中窥豹系列之Runner(三)
2021-01-11 09:54
441 查看
一、前言
- 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源码解析-管中窥豹系列之排序(五)
- springboot源码解析-管中窥豹系列之web服务器(七)
- springboot源码解析-管中窥豹系列之Initializer(四)
- springboot源码解析-管中窥豹系列
- springboot源码解析-管中窥豹系列之BeanDefinition(八)
- springboot源码解析-管中窥豹系列之aware(六)
- Spring Boot系列(三):Spring Boot整合Mybatis源码解析
- Spring Boot系列(四):Spring Boot源码解析
- 深入Spring源码系列--Spring/Springboot 注解失效原因解析
- logback:输出日志到文件(滚动)&& Spring Boot干货系列:(七)默认日志logback配置解析(转载)
- spring boot 源码解析52-actuate中MVCEndPoint解析
- 曹工说Spring Boot源码(15)-- Spring从xml文件里到底得到了什么(context:load-time-weaver 完整解析)
- Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)
- Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)
- Spring Boot干货系列:(二)配置文件解析
- SpringBoot 源码解析——源码下载
- Spring Boot系列(二):Spring Boot自动装配原理解析
- Spring系列(一):Spring MVC bean 解析、注册、实例化流程源码剖析
- SpringBoot2.x系列教程(四十九)Spring Boot中JdbcTemplate源码分析
- SpringBoot 源码解析 (八)----- Spring Boot 精髓:事务源码解析