【Spring系列】应用启动后回调机制CommandLineRunner和ApplicationRunner接口

您所在的位置:网站首页 接口回调的定义和作用 【Spring系列】应用启动后回调机制CommandLineRunner和ApplicationRunner接口

【Spring系列】应用启动后回调机制CommandLineRunner和ApplicationRunner接口

2023-09-17 10:14| 来源: 网络整理| 查看: 265

目录 一、前言二、CommandLineRunner 接口说明三、ApplicationRunner 接口说明三、执行顺序四、注意事项

一、前言

如果我们想在应用启动时,搞事情,并且在整个应用生命周期只搞一次,有什么办法呢?比如在应用启动的时候,提前从数据库加载一些数据,提前加载加密证书等。

其实 SpringBoot 有2大法宝可以做到,CommandLineRunner 和 ApplicationRunner 接口。这2个接口里面都只有一个 run 方法,只要实现了这2个接口的类,并且重写了 run 方法,并将它们的实例交由 Spring 容器管理,Spring 容器在启动后,会自动调用执行 run 方法。并且在整个应用生命周期内只会执行一次。

二、CommandLineRunner 接口说明 package org.springframework.boot; @FunctionalInterface public interface CommandLineRunner { void run(String... args) throws Exception; }

我们定义一个类实现 CommandLineRunner 接口,测试下它的调用时机。我们直接用启动类来实现接口,当然你也可以另起一个类来实现 CommandLineRunner,并注入到 Spring 容器中。

@SpringBootApplication public class Application implements CommandLineRunner { public static void main(String[] args) { System.out.println("--- Application main begin to start..."); SpringApplication.run(Application.class, args); System.out.println("--- Application main has start..."); } @Override public void run(String... args) throws Exception { System.out.println("--- CommandLineRunner in Application..."); } }

启动日志如下,证明确实会在应用启动时,即 Spring 容器加载完后,执行我们定义的 run 方法,执行完成后项目启动完成。

--- Application main begin to start... . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.8.RELEASE) // 省略一些日志 2021-02-20 14:10:02.473 INFO 25240 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2021-02-20 14:10:02.486 INFO 25240 --- [ restartedMain] com.nobody.Application : Started Application in 1.871 seconds (JVM running for 2.598) --- CommandLineRunner in Application... --- Application main has start...

此时可能有人会问,run 方法的 String... args 参数是干嘛用的,它的值又是哪里来的?其实它就是 main 方法的 String[] args 参数,我们在 main 和 run 方法打印输出看看。

@SpringBootApplication public class Application implements CommandLineRunner { public static void main(String[] args) { System.out.println("--- Application main begin to start..."); System.out.println("main args length=" + args.length + ", args=" + Arrays.toString(args)); SpringApplication.run(Application.class, args); System.out.println("--- Application main has start..."); } @Override public void run(String... args) throws Exception { System.out.println("--- CommandLineRunner in Application..."); System.out.println("run args length=" + args.length + ", args=" + Arrays.toString(args)); } }

然后启动先配置下应用启动时传的参数,如下: 在这里插入图片描述 启动服务,启动日志如下,验证正确。

--- Application main begin to start... main args length=2, args=[Mr.nobody, Cx330] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.8.RELEASE) // 省略一些日志 --- CommandLineRunner in Application... run args length=2, args=[Mr.nobody, Cx330] --- Application main has start... 三、ApplicationRunner 接口说明

其实 ApplicationRunner 接口和 CommandLineRunner 接口作用一样的,唯一不同的是 args 参数。CommandLineRunner 的 run 方法参数是 String… args,而 ApplicationRunner 的 run 方法参数是 ApplicationArguments args。

@SpringBootApplication public class Application implements ApplicationRunner { public static void main(String[] args) { System.out.println("--- Application main begin to start..."); System.out.println("main args length=" + args.length + ", args=" + Arrays.toString(args)); SpringApplication.run(Application.class, args); System.out.println("--- Application main has start..."); } @Override public void run(ApplicationArguments args) throws Exception { System.out.println("--- CommandLineRunner in Application..."); System.out.println("run args optionNames=" + args.getOptionNames() + ", sourceArgs=" + Arrays.toString(args.getSourceArgs()) + ", name=" + args.getOptionValues("name")); } }

在这里插入图片描述 服务启动后,启动日志如下:

--- Application main begin to start... main args length=2, args=[--name=Mr.nobody, --age=18] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.8.RELEASE) // 省略一些日志 --- CommandLineRunner in Application... run args optionNames=[name, age], sourceArgs=[--name=Mr.nobody, --age=18], name=[Mr.nobody] --- Application main has start... 三、执行顺序

如果在启动服务的时候需要初始化很多资源,并且要保证初始化资源相互之间有序,那如何保证不同的 CommandLineRunner 的执行顺序呢? 如果定义了多个 CommandLineRunner,可以实现 Ordered 接口,或者使用 @Order 注解。我们可以指定 Order 里的值,数字越小越早执行。

而且,CommandLineRunner 和 ApplicationRunner 是可以共存的。

@SpringBootApplication // 注解指定执行顺序 @Order(0) public class Application implements CommandLineRunner { public static void main(String[] args) { System.out.println("--- Application main begin to start..."); SpringApplication.run(Application.class, args); System.out.println("--- Application main has start..."); } @Override public void run(String... args) throws Exception { System.out.println("--- CommandLineRunner in Application, Order=0 ..."); } } @Component // 注解指定执行顺序 @Order(1) public class MyCommandLineRunner1 implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("--- CommandLineRunner in MyCommandLineRunner1, Order=1 ..."); } } @Component // @Order(2) // 实现 Ordered 接口,并且重写 getOrder 方法 public class MyCommandLineRunner2 implements CommandLineRunner, Ordered { @Override public void run(String... args) throws Exception { System.out.println("--- CommandLineRunner in MyCommandLineRunner2, Order=2 ..."); } // 指定执行顺序 @Override public int getOrder() { return 2; } } @Component @Order(3) public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("--- ApplicationRunner in MyApplicationRunner, Order=3 ..."); } }

启动服务,启动日志如下:

--- Application main begin to start... . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.8.RELEASE) // 省略一些日志 --- CommandLineRunner in Application, Order=0 ... --- CommandLineRunner in MyCommandLineRunner1, Order=1 ... --- CommandLineRunner in MyCommandLineRunner2, Order=2 ... --- ApplicationRunner in MyApplicationRunner, Order=3 ... --- Application main has start... 四、注意事项 应用启动时,即 Spring 容器加载完后,才执行 run 方法,并且整个应用生命周期只会执行一次。因为 Spring 容器加载完后,才执行 run 方法,所以我们可以在 CommandLineRunner 接口里注入其他依赖(例如 @Autowired 注入),并且使用它们。run 方法如果抛异常,会导致应用启动失败。如果允许,可以使用 try catch 块处理。如果实现 CommandLineRunner 或 ApplicationRunner 接口的类,没有将其注入到 Spring 容器管理(例如没有在类上添加 @Component 注解),是不起作用的。

此演示项目已上传到Github,如有需要可自行下载,欢迎 Star 。 https://github.com/LucioChn/spring-annotation



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3