世界杯预选赛预测

一、前言

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 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源码解析-管中窥豹系列之项目类型(二)

springboot源码解析-管中窥豹系列之Runner(三)

springboot源码解析-管中窥豹系列之Initializer(四)

springboot源码解析-管中窥豹系列之排序(五)

springboot源码解析-管中窥豹系列之aware(六)

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

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

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

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

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

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

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

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

欢迎关注公众号:丰极,更多技术学习分享。