Spring Boot-9-启动加载器

在我们的日常开发中,可能需要在容器启动之后,立马做一些事情,这时候就可以借助 Spring Boot 的启动加载器去实现.

启动加载器

启动加载器有两种方式实现,分别是实现 CommandLineRunnerApplicationRunner ,然后重写里面的 run 方法

实现CommandLineRunner方式

新建类 FirstCommandLineRunner 然后实现 CommandLineRunner ,代码如下:

1
2
3
4
5
6
7
8
9
10
11
@Component
@Order(1)
@Slf4j
public class FirstCommandLineRunner implements CommandLineRunner {

@Override
public void run(String... args) throws Exception {
log.info("First CommandLineRunner ...");
}

}

再搞一个 SecondCommandLineRunner

1
2
3
4
5
6
7
8
9
10
11
@Component
@Order(2)
@Slf4j
public class SecondCommandLineRunner implements CommandLineRunner {

@Override
public void run(String... args) throws Exception {
log.info("Second CommandLineRunner ...");
}

}

然后启动项目, 控制台输出如下:

1
2
3
2020-02-13 18:15:55.765  INFO 32312 --- [           main] com.zhou.springboot.example.App          : Started App in 3.444 seconds (JVM running for 8.238)
2020-02-13 18:15:55.768 INFO 32312 --- [ main] c.z.s.e.startup.FirstCommandLineRunner : First CommandLineRunner ...
2020-02-13 18:15:55.768 INFO 32312 --- [ main] c.z.s.e.startup.SecondCommandLineRunner : Second CommandLineRunner ...

可以看到这里的启动加载器已经正常执行,而且执行顺序只需要通过 @Order 注解来指定执行顺序即可

再来看下第二种方式

实现ApplicationRunner方式

新建类 FirstApplicationRunner 实现 ApplicationRunner ,如下:

1
2
3
4
5
6
7
8
9
10
11
@Component
@Slf4j
@Order(1)
public class FirstApplicationRunner implements ApplicationRunner {

@Override
public void run(ApplicationArguments args) throws Exception {
log.info("first application runner...");
}

}

同样的再搞一个

1
2
3
4
5
6
7
8
9
10
11
@Component
@Slf4j
@Order(2)
public class SecondApplicationRunner implements ApplicationRunner {

@Override
public void run(ApplicationArguments args) throws Exception {
log.info("second application runner...");
}

}

同样的这种方式的执行顺序也是通过 @Order 指定的

执行顺序

上面四个启动加载器 FirstApplicationRunnerFirstCommandLineRunnerOrder 值都是1, 然后 SecondApplicationRunnerSecondCommandLineRunnerOrder 值都是2, 启动项目看以下这四个的执行顺序

1
2
3
4
2020-02-13 18:15:55.767  INFO 32312 --- [           main] c.z.s.e.startup.FirstApplicationRunner   : first application runner...
2020-02-13 18:15:55.768 INFO 32312 --- [ main] c.z.s.e.startup.FirstCommandLineRunner : First CommandLineRunner ...
2020-02-13 18:15:55.768 INFO 32312 --- [ main] c.z.s.e.startup.SecondApplicationRunner : second application runner...
2020-02-13 18:15:55.768 INFO 32312 --- [ main] c.z.s.e.startup.SecondCommandLineRunner : Second CommandLineRunner ...

这里可以看到,在 Order 值相同的情况下, ApplicationRunner 要优先于 CommandLineRunner 执行

原因是什么,下面来看一下启动加载器的源码

源码跟踪

还是先进入启动类的run方法,如下:

image

然后再进入 callRunners() 方法

image

具体调用源码就是这样,比较简单

总结

实现启动加载器的两种方式:

  1. 实现 ApplicationRunner 接口,重写 run() 方法
  2. 实现 CommandLineRunner 接口,重写 run() 方法

执行优先级

  • Order 值相同的情况下, ApplicationRunner 要优先于 CommandLineRunner 执行