在开发Spring Boot应用程序时,有时我们需要在启动时运行方法或一段代码。这段代码可以是任何内容,从记录某些信息到设置数据库,cron作业等。我们不能仅将此代码放入构造函数中,因为所需的变量或服务可能尚未初始化。这可能导致空指针或其他一些异常。
为什么我们需要在Spring Boot启动时运行代码?
由于多种原因,我们需要在应用程序启动时运行方法,
- 记录重要的事情或说应用程序已启动的消息
- 处理数据库或文件,建立索引,创建缓存等。
- 启动后台进程,例如发送通知,从某些队列中获取数据等。
在Spring Boot中启动后运行方法的不同方法
每种方式都有其自身的优势。让我们详细看一下以确定应该使用哪个,
- 使用CommandLineRunner界面
- 带有ApplicationRunner界面
- Spring Boot应用程序事件
- @Postconstruct方法的注释
- InitializingBean接口
- @bean批注的Init属性
1.使用CommandLineRunner界面
CommandLineRunner是一个弹簧启动功能界面,用于在应用程序启动时运行代码。它位于软件包org.springframework.boot下。
在上下文初始化之后的启动过程中,spring boot使用提供给应用程序的命令行参数调用其run()方法。
要通知spring boot我们的commandlineRunner接口,我们可以实现它并在类上方添加@Component批注,或者使用@bean创建其bean。
实现CommandLineRunner接口的示例
@Component public class CommandLineRunnerImpl implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("In CommandLineRunnerImpl "); for (String arg : args) { System.out.println(arg); } } }
创建CommandLineRunner接口Bean的示例
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class); } @Bean public CommandLineRunner CommandLineRunnerBean() { return (args) -> { System.out.println("In CommandLineRunnerImpl "); for (String arg : args) { System.out.println(arg); } }; } }
我们可以使用命令行或IDE运行应用程序。让我们举一个例子,当我们使用参数“ –status = running”运行应用程序时
mvn spring-boot:run -Dspring-boot.run.arguments="--status=running"
要么
mvn package java -jar target/<FILENAME.JAR HERE> --status=running
这将产生以下日志输出:
In CommandLineRunnerImpl status=running
如我们所见,该参数未解析,而是解释为单个值“ status = running”。
要访问已解析格式的命令行参数,我们需要使用ApplicationRunner接口。我们待会儿再看。
Spring Boot将CommandLineRunner接口添加到启动过程中。因此,在commandlinerRunner中引发异常将迫使Spring启动中止启动。
我们可以在一个应用程序中创建多个CommandLineRunner。使用Ordered接口或@Order批注,我们可以配置它们的运行顺序。较低的值表示较高的优先级。默认情况下,所有组件均以最低优先级创建。这就是为什么没有订单配置的组件将被最后调用的原因。
我们可以使用订单注释,如下所示
@Component @Order(1) public class CommandLineRunnerImpl implements CommandLineRunner { ........ }
2.具有ApplicationRunner界面
如前所述,要访问已解析的参数,我们需要使用ApplicationRunner接口。ApplicationRunner接口为运行方法提供ApplicationArguments而不是原始字符串数组。
ApplicationArguments是一个接口,可从org.springframework.boot软件包下的boot 1.3 srping中获得。
它提供了以下几种访问参数的方法
String [] GetSourceArgs() | 提供传递给应用程序的未处理参数 |
Set <String> getOptionNames() | 所有可选参数的名称,可选参数的前面都有“ - “如:-name =‘堆栈跟踪’ |
List <String> getNonOptionArgs() | 返回未处理的非可选参数。不带“ — ”的参数 |
布尔containsOption(字符串名称) | 检查在可选参数中是否存在名称 |
List <String> getOptionValues(字符串名称) | 通过名称给出参数值 |
方法getOptionValues返回值列表,因为参数值可以是数组,因为我们可以在命令行中多次使用同一键。
例如–name =“ stacktrace” —端口= 8080 –name =“ guru”
作为接口实现的应用程序运行器示例
让我们使用“ status = running –mood = happy 10 –20”参数运行以下程序,并了解输出
@Component public class ApplicationRunnerImpl implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("ApplicationRunnerImpl Called"); //print all arguemnts: arg: status=running, arg: --mood=happy, 10, --20 for (String arg : args.getSourceArgs()) { System.out.println("arg: "+arg); } System.out.println("NonOptionArgs: "+args.getNonOptionArgs()); //[status=running,10] System.out.println("OptionNames: "+args.getOptionNames()); //[mood, 20] System.out.println("Printing key and value in loop:"); for (String key : args.getOptionNames()) { System.out.println("key: "+key); //key: mood //key: 20 System.out.println("val: "+args.getOptionValues(key)); //val:[happy] //val:[] } } }
输出:
ApplicationRunnerImpl Called arg: status=running arg: --mood=happ arg: 10 arg: --20 NonOptionArgs: [status=running , 10] OptionNames: [mood, 20] Printing key and value in loop: key: mood val: [happy] key: 20 val: []
CommandLineRunner和ApplicationRunner具有类似的功能,例如
- run()方法中的异常将中止应用程序启动
- 可以使用Ordered接口或@Order批注来订购多个ApplicationRunner
需要注意的最重要一点是,命令在CommandLineRunners和ApplicationRunners之间共享。这意味着可以在commandlinerRunner和applicationRunner之间混合执行顺序。