在《Springboot源码解读与原理分析》中看到下面描述:

整个SpringApplication的启动逻辑非常复杂,核心步骤大概分为以下8步:
1.获取SpringApplicationRunListener监听器,该监听器会贯穿整个Spring Application的启动过程。
2.准备运行时环境,即ApplicationContext中的Environment。
3.Banner的加载与打印,默认情况下打印的Banner是以文字形式打印到控制台,可以通过定制SpringApplication来自定义配置。
4.创建ApplicationContext IOC容器,该步骤创建的依据是创建Spring Application时推断的Web应用类型,不同的Web应用类型对应不同的Application Context落地实现。
5.初始化IOC容器,该步骤会应用前面步骤准备的ApplicationContext Initializer,并获取和加载配置源(默认是主启动类)。
6.刷新IOC容器,该步骤会触发ApplicationContext的核心refresh方法,逻辑极其复杂。
7.启动嵌入式Web容器(如果有的话),当Web应用类型不是None并且以独立运行的jar包运行Spring Boot时,底层会额外创建一个嵌入式Web容器(默认是Tomcat)并启动。
8.回调Spring Boot的运行器,包括ApplicationRunner和CommandLineRunner。

我们通常使用ApplicationRunner和CommandLineRunner来加载缓存数据或做其他初始化动作。这二者的区别是什么呢?

通过运行下面Java代码,我们发现ApplicationRunner的执行时机要比CommandLineRunner早。

@Slf4j
@Component
public class ApplicationRunnerTest implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunner , args:{}", JSON.toJSONString(args));
    }
}

@Component
@Slf4j
public class CommandLineRunnerTest implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("CommandLineRunner , args:{}", JSON.toJSONString(args));
    }
}

运行截图:
image.png

两者都是在Spring Boot 应用程序启动后,容器初始化完成后执行。默认执行顺序是ApplicationRunner要早于CommandLineRunner。
当然我们可以通过@Order注解去调整执行顺序。
image.png

第二个区别是ApplicationRunner对args参数提供了更高级的封装,CommandLineRunner提供了原始参数字符串。