一、前言
很久很久以前,在 servlet / jsp 项目中,如果是涉及到系统启动任务,例如:在项目刚启动的时候进行一些数据初始化操作,这类操作都有着一个共性,那就是只在项目刚启动时执行一次,后面不再执行。
当然,那些经历过 servlet / jsp 的朋友,脑袋立马能浮现Web基础中的三大组件(Servlet、Filter、Listener)中的Listener(监听器)。一般情况,定义一个ServletContextListener
,便可以监听到项目的启动、销毁,这样方便对数据进行初始化、销毁操作。如下:
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//启动后执行,在这里做数据初始化操作
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//销毁前执行,可以在这里做数据备份操作
}
}
上面提到只是基础的Web项目解决方案,现在使用了SpringBoot项目,这种操作更简单了。在SpringBoot项目中,针对定义系统启动任务,提供了两种方案,分别是:CommandLineRunner
、ApplicationRunner
。
接下来,就分别来看看这两种解决方案。
二、CommandLineRunner
首先,我们创建一个MyCommandLineRunner01
类,并且实现CommandLineRunner
接口,如下:
@Component
@Order(100)
public class MyCommandLineRunner01 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.err.println("MyCommandLineRunner01>>>" + Arrays.toString(args));
}
}
下面,就对这段代码进行说明,如下:
@Component
注解:表示将MyCommandLineRunner01
类注册成为Spring容器中的一个Bean。@Order
注解:表示该启动任务的执行优先级,因为,在一个项目中,可能存在着多个启动任务,所以需要定义优先级。@Order
注解中的整数值越小,优先级越高,默认值是Integer_MAXVALUE
,表示优先级最低。run
方法中,是用来写启动任务的核心业务逻辑的,启动项目时,run
方法会被执行。run
方法中的参数,来自于项目的启动参数,即项目启动类中main
方法的参数会被传递到此。
【命令行启动项目】
另一种传参方式,是先将项目打包,使用命令行启动项目时,并传入参数,如下:
java -jar commandlinerunner-0.0.1-SNAPSHOT.jar 武汉加油 中国加油
值得注意的是,这里传参没有key,只有value,所以多个value用空格隔开即可,运行结果如下:
三、ApplicationRunner
其实,CommandLineRunner
和ApplicationRunner
的功能相同,用法也相同,唯一的区别主要体现在对参数的处理上,ApplicationRunner
可以接收更多类型的参数(ApplicationRunner
除了可以接收CommandLineRunner
中类型的参数外,还能接收key-value
形式的参数)。
使用ApplicationRunner
除了实现的接口不同之外,其他用法和CommandLineRunner
都是一样的,如下:
@Component
@Order(100)
public class MyApplicationRunner01 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
String[] sourceArgs = args.getSourceArgs();
System.err.println("sourceArgs>>>"+ Arrays.toString(sourceArgs));
List<String> nonOptionArgs = args.getNonOptionArgs();
System.err.println("nonOptionArgs>>>"+nonOptionArgs);
Set<String> optionNames = args.getOptionNames();
System.err.println(">>>>>>>>>>>>>>>>MyApplicationRunner01开始>>>>>>>>>>>>>>>>>");
for (String optionName : optionNames) {
System.err.println(optionName+":"+args.getOptionValues(optionName));
}
System.err.println(">>>>>>>>>>>>>>>>>MyApplicationRunner01结束>>>>>>>>>>>>>>>>");
}
}
和CommandLineRunner
中run
方法相同,都是在项目启动时被执行,但是不同的是run
方法的参数,关于ApplicationArguments
参数,可以来看看该类型的参数中有哪些方法,作用分别是什么?
args.getSourceArgs()
:表示获取所有的参数。args.getNonOptionArgs()
:表示获取参数中非key-value的参数(与CommandLineRunner
中相同)。args.getOptionNames()
:表示获取参数中key-value形式的参数的key。args.getOptionValues()
:表示获取参数中key-value形式的参数的value。
ApplicationArguments
定义完成后,传启动参数也是两种方式,非key-value形式的参数和CommandLineRunner
中相同,对于key-value形式的参数,IDEA中如此定义,如下:
java -jar applicationrunner-0.0.1-SNAPSHOT.jar --name=mango --address=www.mango.com 武汉加油 中国加油
注意,这里的key-value形式的参数格式为:--key=value
,非key-value形式参数与CommandLineRunner
中相同,运行结果如下:
四、总结
经过两种方式的实践,可以看出两者之间主要在于对参数的处理不同,ApplicationRunner
> CommandLineRunner
,至于如何选择,就看项目中具体的需求了。
五、源码地址
CommandLineRunner源码地址:CommandLineRunner
ApplicationRunner源码地址:ApplicationRunner