有道无术,术尚可求,有术无道,止于术。
本系列Spring Boot版本2.7.0
在应用程序启动后,需要执行特定的代码,比如加载缓存数据、打印自定义启动信息等。
Spring Boot 为我们提供了ApplicationRunner、CommandLineRunner两个接口来实现上面的需求。
在应用程序启动类SpringApplication的run方法中,可以看到在最后调用了一个callRunners方法:

在callRunners方法中,会在上下文中查询ApplicationRunner和CommandLineRunner类型的Bean 对象,并调用他们的run 方法运行:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
由此可见,我们只需要注册ApplicationRunner和CommandLineRunner类型的Bean ,就可以实现在应用启动最后阶段执行特定的代码。
ApplicationRunner只定义了一个run方法用于在启动完成后进行方法调用,可以定义多个该类型的Bean ,并且可以通过实现Ordered接口或使用@Order注解进行排序。
run方法接收一个ApplicationArguments ,也就是应用启动参数,参数具体用法可以参考SpringApplication启动参数使用详解。
@FunctionalInterface
public interface ApplicationRunner {
// 用于运行 bean 的回调
void run(ApplicationArguments args) throws Exception;
}
案例演示:在应用程序启动完成时,加载字典缓存、打印当前应用的访问地址。
首先加载缓存,并使用@Order(1)进行排序:
@Order(1)
@Component
public class DictCacheInitializerApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("应用启动完成,开始初始化字典缓存....");
System.out.println("加载中....");
System.out.println("初始化完成....");
}
}
再编写一个打印访问地址的运行器,设置排序为2:
@Component
@Order(2)
public class AddressInitializerApplicationRunner implements ApplicationRunner {
@Value("${server.port}")
String port;
@Override
public void run(ApplicationArguments args) {
System.out.println("应用访问地址:http://localhost:" + port);
}
}
启动程序,可以看到在启动完成后执行了响应的代码,@Order数值越小越先执行:

CommandLineRunner和ApplicationRunner作用用法一样,区别在于他们的参数不同,CommandLineRunner传入的参数是原始的参数集合,比如--name=zhangsan,所以一般很少用到,也就不赘述了。
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}