前言
如果想在SpringApplication启动后做一些操作,那么除了可以监听ApplicationReadyEvent事件外,还可以实现ApplicationRunner或CommandLineRunner接口.
ApplicationRunner
新建一个ApplicationRunner实现,代码如下:
java复制代码package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* 自定义{@link ApplicationRunner}实现
*
* @author Bruse
*/
@Slf4j
@Component
public class CustomApplicationRunner implements ApplicationRunner {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(ApplicationArguments args) throws Exception {
// 简单打印一下应用参数
log.info("arguments is {}", Arrays.toString(args.getSourceArgs()));
}
}
这里ApplicationRunner的run()方法实现,仅仅打印一下应用参数,所以在启动Java Application前,先在配置一些应用参数【笔者这里用到的IDEA版本为2023.1.4】:
启动SpringApplication,输出如下:
可以看到CustomApplicationRunner的run()方法在SpringApplicaiton启动后被回调,并且输出我们配置的应用参数.
CommandLineRunner
新建一个CommandLineRunner实现,代码如下:
java复制代码package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 自定义{@link CommandLineRunner}实现
*/
@Slf4j
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(String... args) throws Exception {
// 这里简单做一下参数打印
log.info("args is {}", Arrays.toString(args));
}
}
启动SpringApplication,控制台成功输出:
两者的区别
ApplicationRunner和CommandLineRunner两个接口唯一的区别在于,两者run()方法的参数不一样,虽然参数都是Java应用启动时设置的参数,但ApplicationRunner将参数包装成了ApplicationArguments,CommandLineRunner则没有多过包装,直接就是传递一个String[]给实现者进行参数读取.
优先级设置
如果必须按特定顺序调用ApplicationRunner或CommandLineRunner的run()方法的话,可以使用Order注解或实现Ordered接口.
对CustomApplicationRunner稍作调整,让其实现Ordered接口,改动后代码如下:
java复制代码package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 自定义{@link ApplicationRunner}实现
*
* @author Bruse
*/
@Slf4j
@Component
public class CustomApplicationRunner implements ApplicationRunner, Ordered {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("arguments is {}", Arrays.toString(args.getSourceArgs()));
}
@Override
public int getOrder() {
// 返回优先级,数值越小,优先级越高
return 0;
}
}
对CustomCommandLineRunner稍作调整,给其加上@Order注解,代码如下:
java复制代码package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 自定义{@link CommandLineRunner}实现
*/
@Slf4j
@Order(-1) // 数值越小,优先级越高
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(String... args) throws Exception {
log.info("args is {}", Arrays.toString(args));
}
}
CustomCommandLineRunner定义的优先级比CustomApplicationRunner高,也就是CustomCommandLineRunner的run()永远优于CustomApplicationRunner的run(),控制台输出如下:
注意不要做耗时的任务
本质上启动SpringApplication的线程,和回调ApplicationRunner、CommandLineRunner的run()方法的线程是同一个,所以注意不要在run()中执行过于复杂耗时的任务.
源码分析
查看SpringApplication的run()方法,关键代码如下:
查看callRunners()方法,可以看到逻辑非常简单,就是获取所有ApplicationRunner和CommandLineRunner的实现,然后做一个优先级排序,最后回调run()方法.
而且从源码中还可以看出,ApplicationRunner和CommandLineRunner的run()回调,是在ApplicationReadyEvent事件广播之前,核心代码如下: