经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
Spring Boot 中的 ApplicationRunner 和 CommandLineRunner
来源:cnblogs  作者:god23bin  时间:2023/3/29 10:08:44  对本文有异议

前言

一般项目中的初始化操作,初次遇见,妙不可言。如果你还有哪些方式可用于初始化操作,欢迎在评论中分享出来~

ApplicationRunner 和 CommandLineRunner

Spring Boot 应用,在启动的时候,如果想做一些事情,比如预先加载并缓存某些数据,读取某些配置等等。总而言之,做一些初始化的操作时,那么 Spring Boot 就提供了两个接口帮助我们实现。

这两个接口是:

  • ApplicationRunner 接口
  • CommandLineRunner 接口

源码如下:

ApplicationRunner

  1. package org.springframework.boot;
  2. import org.springframework.core.Ordered;
  3. import org.springframework.core.annotation.Order;
  4. /**
  5. * Interface used to indicate that a bean should <em>run</em> when it is contained within
  6. * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
  7. * within the same application context and can be ordered using the {@link Ordered}
  8. * interface or {@link Order @Order} annotation.
  9. *
  10. * @author Phillip Webb
  11. * @since 1.3.0
  12. * @see CommandLineRunner
  13. */
  14. @FunctionalInterface
  15. public interface ApplicationRunner {
  16. /**
  17. * Callback used to run the bean.
  18. * @param args incoming application arguments
  19. * @throws Exception on error
  20. */
  21. void run(ApplicationArguments args) throws Exception;
  22. }

CommandLineRunner

  1. package org.springframework.boot;
  2. import org.springframework.core.Ordered;
  3. import org.springframework.core.annotation.Order;
  4. /**
  5. * Interface used to indicate that a bean should <em>run</em> when it is contained within
  6. * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
  7. * within the same application context and can be ordered using the {@link Ordered}
  8. * interface or {@link Order @Order} annotation.
  9. * <p>
  10. * If you need access to {@link ApplicationArguments} instead of the raw String array
  11. * consider using {@link ApplicationRunner}.
  12. *
  13. * @author Dave Syer
  14. * @since 1.0.0
  15. * @see ApplicationRunner
  16. */
  17. @FunctionalInterface
  18. public interface CommandLineRunner {
  19. /**
  20. * Callback used to run the bean.
  21. * @param args incoming main method arguments
  22. * @throws Exception on error
  23. */
  24. void run(String... args) throws Exception;
  25. }

可以看到,这两个接口的注释几乎一模一样,如出一辙。大致的意思就是,这两个接口可以在 Spring 的环境下指定一个 Bean 运行(run)某些你想要做的事情,如果你有多个 Bean 进行指定,那么可以通过 Ordered 接口或者 @Order 注解指定执行顺序。

说白了,就是可以搞多个实现类实现这两个接口,通过 @Order 确定实现类的谁先运行,谁后运行

@Order

再看看 @Order 注解的源码:

  1. /**
  2. * {@code @Order} defines the sort order for an annotated component.
  3. *
  4. * <p>The {@link #value} is optional and represents an order value as defined in the
  5. * {@link Ordered} interface. Lower values have higher priority. The default value is
  6. * {@code Ordered.LOWEST_PRECEDENCE}, indicating lowest priority (losing to any other
  7. * specified order value).
  8. * ..... 省略剩下的注释
  9. */
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
  12. @Documented
  13. public @interface Order {
  14. /**
  15. * The order value.
  16. * <p>Default is {@link Ordered#LOWEST_PRECEDENCE}.
  17. * @see Ordered#getOrder()
  18. */
  19. int value() default Ordered.LOWEST_PRECEDENCE;
  20. }

Ordered.LOWEST_PRECEDENCE 的默认值是 Integer.MAX_VALUE

在顶部的注释中,可以知道,@Order 注解是给使用了 @Component 注解的 Bean 定义排序顺序(defines the sort order for an annotated component),然后 @Order 注解的 value 属性值越低,那么代表这个 Bean 有着更高的优先级(Lower values have higher priority)。

测试

分别写两个实现类,实现这两个接口,然后启动 Spring Boot 项目,看看执行顺序

ApplicationRunnerImpl:

  1. @Slf4j
  2. @Component
  3. public class ApplicationRunnerImpl implements ApplicationRunner {
  4. @Override
  5. public void run(ApplicationArguments args) throws Exception {
  6. log.info("我正在加载 ------------------> ApplicationRunnerImpl");
  7. }
  8. }

CommandLineRunnerImpl:

  1. @Slf4j
  2. @Component
  3. public class CommandLineRunnerImpl implements CommandLineRunner {
  4. @Override
  5. public void run(String... args) throws Exception {
  6. log.info("我正在加载 ------------------> CommandLineRunnerImpl");
  7. }
  8. }

控制台输出:

  1. 2023-03-26 15:46:38.344 INFO 25616 --- [ main] c.g.demo.init.ApplicationRunnerImpl : 我正在加载 ------------------> ApplicationRunnerImpl
  2. 2023-03-26 15:46:38.344 INFO 25616 --- [ main] c.g.demo.init.CommandLineRunnerImpl : 我正在加载 ------------------> CommandLineRunnerImpl

可以看到,是 ApplicationRunnerImpl 先运行的,CommandLineRunnerImpl 后运行的。

我们给 CommandLineRunnerImpl 加上 @Order 注解,给其 value 属性设置 10:

  1. @Slf4j
  2. @Order(10)
  3. @Component
  4. public class CommandLineRunnerImpl implements CommandLineRunner {
  5. @Override
  6. public void run(String... args) throws Exception {
  7. log.info("我正在加载 ------------------> CommandLineRunnerImpl");
  8. }
  9. }

控制台输出:

  1. 2023-03-26 15:50:43.524 INFO 16160 --- [ main] c.g.demo.init.CommandLineRunnerImpl : 我正在加载 ------------------> CommandLineRunnerImpl
  2. 2023-03-26 15:50:43.524 INFO 16160 --- [ main] c.g.demo.init.ApplicationRunnerImpl : 我正在加载 ------------------> ApplicationRunnerImpl

区别

回到这两个接口,看似一模一样,但肯定有小小区别的,最主要的区别就是接口的抽象方法的参数

ApplicationRunner:

  • void run(ApplicationArguments args) throws Exception;

CommandLineRunner:

  • void run(String... args) throws Exception;

具体来说,ApplicationRunner 接口的 run 方法中的参数为 ApplicationArguments 对象,该对象封装了应用程序启动时传递的命令行参数和选项。

CommandLineRunner 接口的 run 方法中的参数为 String 数组,该数组直接包含了应用程序启动时传递的命令行参数和选项。

测试

打印下命令行参数:

  1. @Slf4j
  2. @Component
  3. public class ApplicationRunnerImpl implements ApplicationRunner {
  4. @Override
  5. public void run(ApplicationArguments args) throws Exception {
  6. System.out.println("ApplicationRunner: optionNames = " + args.getOptionNames() + ", sourceArgs = " + args.getSourceArgs());
  7. }
  8. }
  1. @Slf4j
  2. @Component
  3. public class CommandLineRunnerImpl implements CommandLineRunner {
  4. @Override
  5. public void run(String... args) throws Exception {
  6. System.out.println("CommandLineRunner: " + Arrays.toString(args));
  7. }
  8. }

用 Maven 打包项目为 Jar 包,启动该 Jar 包:

  1. // 使用 java -jar 启动,加上两个参数:name 和 description
  2. java -jar demo-0.0.1-SNAPSHOT.jar --name=god23bin --description=like_me

输出:

  1. ApplicationRunner: optionNames = [name, description]sourceArgs = [Ljava.lang.String;@5c90e579
  2. CommandLineRunner: [--name=god23bin, --description=like_me]

最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!

最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!

你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

原文链接:https://www.cnblogs.com/god23bin/p/spring_boot_application_runner_and_command_line_runner.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号