一、前言

  • Springboot源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
  • 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的springboot源码管中窥豹系列。

二、Runner

  • 如果咱们想在springboot我的项目启动实现之后,做点什么,咱们应该怎么办呢?
  • 留神咱们能够写在bean的初始化办法外面(咱们前面讲),然而咱们要用到其它曾经加载了的bean的能力,又怎么办呢?
  • 当然加程序,加依赖也能解决,就是麻烦

这一节咱们讨论一下springboot我的项目的Runner,Runner是在spring加载结束执行的,springboot有两种Runner:

  • ApplicationRunner
  • CommandLineRunner
@FunctionalInterfacepublic interface ApplicationRunner {    void run(ApplicationArguments args) throws Exception;}@FunctionalInterfacepublic interface CommandLineRunner {    void run(String... args) throws Exception;}
  • 两种除了参数不同,其它没区别
  • ApplicationArguments是对传参数组的封装,实质也没区别
  • 只有执行程序上有区别,上面源码会看到

三、用法

实现接口就能够了

import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.stereotype.Component;@Componentpublic 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

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