知識改變命運(yùn),擼碼使我快樂烙丛,2020繼續(xù)游走在開源界
點(diǎn)贊再看,養(yǎng)成習(xí)慣
給我來個Star吧,點(diǎn)擊了解下基于SpringBoot的組件化接口服務(wù)落地解決方案
如果你想要使用SpringBoot
構(gòu)建的項(xiàng)目在啟動后運(yùn)行一些特定的代碼紊搪,那么CommandLineRunner
、ApplicationRunner
都是很好的選擇磨总。
推薦閱讀
使用方式
我們以CommandLineRunner
創(chuàng)建了一個簡單的例子嗦明,如下所示:
/**
* {@link CommandLineRunner}接口使用示例
*
* @author 恒宇少年
*/
@Component
public class CommandLineRunnerExample implements CommandLineRunner {
/**
* 實(shí)例化本類的日志采集器
*/
static LoggingCollector logging = LoggingCollectorFactory.getCollector(CommandLineRunnerExample.class);
@Override
public void run(String... args) throws Exception {
// 執(zhí)行特定的代碼
logging.debug("main方法參數(shù)列表:{}", args);
}
}
CommandLineRunner
接口的定義很簡單,只提供了一個名為#run()
的方法蚪燕,我們只需要實(shí)現(xiàn)該方法做一些自定義的業(yè)務(wù)邏輯即可娶牌,ApplicationRunner
接口的使用方式也是一樣的。
兩者的區(qū)別馆纳?
從源碼上分析诗良,CommandLineRunner
與ApplicationRunner
兩者之間只有#run()
方法的參數(shù)不一樣而已。
CommandLineRunner:
@FunctionalInterface
public interface CommandLineRunner {
/**
* Callback used to run the bean.
* @param args incoming main method arguments
* @throws Exception on error
*/
void run(String... args) throws Exception;
}
ApplicationRunner:
@FunctionalInterface
public interface ApplicationRunner {
/**
* Callback used to run the bean.
* @param args incoming application arguments
* @throws Exception on error
*/
void run(ApplicationArguments args) throws Exception;
}
CommandLineRunner#run()
方法的參數(shù)是啟動SpringBoot
應(yīng)用程序main
方法的參數(shù)列表鲁驶,而ApplicationRunner#run()
方法的參數(shù)則是ApplicationArguments
對象鉴裹。
在之前的文章中也提到過ApplicatgionArguments
對象,并使用它獲取外部的配置參數(shù)钥弯,查看:應(yīng)用程序在啟動時訪問啟動項(xiàng)參數(shù)径荔。
建議:如果你在項(xiàng)目啟動時需要獲取類似 "--xxx" 的啟動參數(shù)值建議使用
ApplicationRunner
什么時候會被調(diào)用?
我們已經(jīng)了解CommandLineRunner
與ApplicationRunner
兩個接口的使用以及區(qū)別脆霎,是不是很想知道SpringBoot
在啟動時在什么時候調(diào)用它們的呢总处?
我們大家都知道SpringBoot
應(yīng)用程序的啟動主要?dú)w功于SpringApplication
這個類,我們在創(chuàng)建項(xiàng)目時在啟動類內(nèi)會調(diào)用SpringApplication#run()
方法睛蛛,如下所示:
public static void main(String[] args) {
SpringApplication.run(LoggingServiceApplication.class, args);
}
那我們來查看下SpringApplication
類#run()
方法的源碼鹦马,根據(jù)查看方法之間的相互調(diào)用,最終我們會定位到org.springframework.boot.SpringApplication#run(java.lang.String...)
這個方法忆肾,閱讀該方法時發(fā)現(xiàn)有關(guān)調(diào)用Runner
的定義荸频,如下所示:
// 省略部分源碼
listeners.started(context);
callRunners(context, applicationArguments);
// 省略部分源碼
#callRunnners()
方法的調(diào)用確實(shí)是在應(yīng)用程序啟動完成后,而且把ApplicationContext
與ApplicationArguments
對象都作為參數(shù)進(jìn)行了傳遞客冈,那么我們來看看這個方法究竟干了些什么事情旭从?
SpringApplication#callRunners:
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);
}
}
}
我想大家看到這里就應(yīng)該明白了,這個方法就是在執(zhí)行CommandLineRunner
以及ApplicationRunner
實(shí)現(xiàn)類實(shí)例的#run()
方法,首先會從ApplicationContext
中獲取CommandLineRunner
遇绞、ApplicationRunner
接口實(shí)現(xiàn)類的實(shí)例键袱,然后根據(jù)不同類型的Runner
實(shí)例去調(diào)用了callRunner
方法。
SpringApplication#callRunner:
// 調(diào)用ApplicationRunner實(shí)現(xiàn)類實(shí)例#run()
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
// 調(diào)用CommandLineRunner實(shí)現(xiàn)類實(shí)例#run()
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}
設(shè)置執(zhí)行順序
那如果我們創(chuàng)建了多個CommandLineRunner
摹闽、ApplicationRunner
實(shí)現(xiàn)類蹄咖,還想要實(shí)現(xiàn)類在執(zhí)行的時候有一定的先后順序,那你不妨試下org.springframework.core.annotation.Order
這個注解或者實(shí)現(xiàn)org.springframework.core.Ordered
接口付鹿。
CommandLineRunnerExample:
/**
* {@link CommandLineRunner}接口使用示例
*
* @author 恒宇少年
*/
@Component
@Order(100)
public class CommandLineRunnerExample implements CommandLineRunner, Ordered {
// 省略部分代碼
@Override
public int getOrder() {
return 100;
}
}
接口與注解的方式選擇其中一種就可以了澜汤。