1. 前言

不知道你有没有接到这种需求,项目启动后立马执行一些逻辑。比如简单的缓存预热,或者上线后的广播之类等等。如果你使用 Spring Boot 框架的话就可以借助其提供的接口CommandLineRunnerApplicationRunner来实现。

2. CommandLineRunner

org.springframework.boot.CommandLineRunnerSpring Boot提供的一个接口,当你实现该接口并将之注入Spring IoC容器后,Spring Boot应用启动后就会执行其run方法。一个Spring Boot可以存在多个CommandLineRunner的实现,当存在多个时,你可以实现Ordered接口控制这些实现的执行顺序(Order 数值越大优先级越低)。接下来我们来声明两个实现并指定顺序:

优先执行:

package cn.felord;

import lombok.extern.slf4j.Slf4j;import org.springframework.boot.CommandLineRunner;import org.springframework.core.Ordered;import org.springframework.stereotype.Component;

/** * 优先级最高 * 该类期望在springboot 启动后第一顺位执行 * @author felord.cn * @since 12:57 **/@Slf4j@Componentpublic class HighOrderCommandLineRunner implements CommandLineRunner, Ordered {    @Override    public void run(String... args) throws Exception {        for (String arg : args) {            log.info("arg = " + arg);        }        log.info("i am highOrderRunner");    }

    @Override    public int getOrder() {        return Integer.MIN_VALUE+1;    }}

第二顺序执行:

package cn.felord;

import lombok.extern.slf4j.Slf4j;import org.springframework.boot.CommandLineRunner;import org.springframework.core.Ordered;import org.springframework.stereotype.Component;

/** * 优先级低于{@code HighOrderCommandLineRunner} * @author felord.cn * @since 12:59 **/@Slf4j@Componentpublic class LowOrderCommandLineRunner implements CommandLineRunner, Ordered {

    @Override    public void run(String... args) throws Exception {        log.info("i am lowOrderRunner");    }

    @Override    public int getOrder() {        return Integer.MIN_VALUE+1;    }}

然后启动Spring Boot应用后,控制台按照预定的顺序打印出了结果:

2020-05-30 23:11:03.685  INFO 11976 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''2020-05-30 23:11:03.701  INFO 11976 --- [           main] c.f.Application  : Started SpringBootApplication in 4.272 seconds (JVM running for 6.316)2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.LowOrderCommandLineRunner   : i am lowOrderRunner

3. ApplicationRunner

Spring Boot 1.3.0又引入了一个和CommandLineRunner功能一样的接口ApplicationRunnerCommandLineRunner接收可变参数String... args,而ApplicationRunner 接收一个封装好的对象参数ApplicationArguments。除此之外它们功能完全一样,甚至连方法名都一样。声明一个ApplicationRunner并让它优先级最低:

package cn.felord;

import lombok.extern.slf4j.Slf4j;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.core.Ordered;import org.springframework.stereotype.Component;

import java.util.Arrays;import java.util.List;import java.util.Set;

/** * 优先级最低 * @author felord.cn * @since 13:00 **/@Slf4j@Componentpublic class DefaultApplicationRunner implements ApplicationRunner, Ordered {    @Override    public void run(ApplicationArguments args) throws Exception {        log.info("i am applicationRunner");        Set optionNames = args.getOptionNames();        log.info("optionNames = " + optionNames);        String[] sourceArgs = args.getSourceArgs();        log.info("sourceArgs = " + Arrays.toString(sourceArgs));        List nonOptionArgs = args.getNonOptionArgs();        log.info("nonOptionArgs = " + nonOptionArgs);        List optionValues = args.getOptionValues("foo");        log.info("optionValues = " + optionValues);    }@Overridepublic int getOrder() {return Integer.MIN_VALUE+2;    }}

按照顺序打印了三个类的执行结果:

2020-06-01 13:02:39.420  INFO 19032 --- [           main] c.f.MybatisResultmapApplication  : Started MybatisResultmapApplication in 1.801 seconds (JVM running for 2.266)2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionNames = []2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = []2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = []2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionValues = null

Ordered接口并不能被 @Order注解所代替。

4. 传递参数

相信很多同学看到这里都开始对这两个run方法的入参感兴趣了。Spring Boot应用启动时是可以接受参数的,换句话说也就是Spring Bootmain方法是可以接受参数的。这些参数通过命令行 java -jar yourapp.jar 来传递。CommandLineRunner会原封不动照单全收这些接口,这些参数也可以封装到ApplicationArguments对象中供ApplicationRunner调用。我们来认识一下ApplicationArguments的相关方法:

  • getSourceArgs() 被传递给应用程序的原始参数,返回这些参数的字符串数组。

  • getOptionNames() 获取选项名称的Set字符串集合。如 --spring.profiles.active=dev --debug 将返回["spring.profiles.active","debug"]

  • getOptionValues(String name) 通过名称来获取该名称对应的选项值。如--foo=bar --foo=baz 将返回["bar","baz"]

  • containsOption(String name) 用来判断是否包含某个选项的名称。

  • getNonOptionArgs() 用来获取所有的无选项参数。

    接下来我们试验一波,你可以通过下面的命令运行一个 Spring Boot应用 Jar

java -jar yourapp.jar --foo=bar --foo=baz --dev.name=码农小胖哥 java felordcn

或者在IDEA开发工具中打开Spring Boot应用main方法的配置项,进行如下配置,其他IDE工具同理。


运行Spring Boot应用,将会打印出:

2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=bar2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=baz2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --dev.name=码农小胖哥2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = java2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = felordcn2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionNames = [dev.name, foo]2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = [--foo=bar, --foo=baz, --dev.name=码农小胖哥, java, felordcn]2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = [java, felordcn]2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionValues = [bar, baz]

然后你就可以根据实际需要动态地执行一些逻辑。

5. 总结

今天我们对CommandLineRunnerApplicationRunner进行了讲解,从用法到顺序执行,又对Spring Boot传递参数进行了介绍和演示,希望对你有所帮助。多多关注:码农小胖哥,更多编程干货分享给你。

往期推荐:

写着写着代码就被带上了警车

Java设计模式之命令模式

docker启动后自动退出_Spring Boot项目启动后如何自动执行逻辑相关推荐

  1. 项目启动时socket自动启动_spring boot 项目在启动时调用接口

    1.环境 目前开发的项目使用的spring boot(2.1.4.RELEASE)+ssm 2. 需求 现在有一个数据处理任务的接口,在spring boot项目启动后,可以手动的去启动任务,但是这样 ...

  2. java项目启动后运行方法_spring boot在启动项目之后执行的实现方法

    前言 我们在web项目启动之后有时候还会做点其它的东西(比如,导入数据脚本),下面就说说spring-boot里怎么在程序启动后加入自己要执行的东西 方法如下: 新建一个类:BeforeStartup ...

  3. Spring Boot项目启动的几种方式

    Spring Boot项目启动的几种方式 方式一:右击启动或者点击intellij右上角的启动按钮 我们访问下浏览器看一下效果 方式二:利用maven启动 我们先进入到项目文件下,然后执行命令   m ...

  4. springboot 修改了端口不生效_Spring Boot 项目 Docker 化快速上手

    开篇 服务部署是应用上线前的必需环节.大道至简,如何做到项目简单化.自动化甚至傻瓜式部署是考验DevOps的一大难题.从docker面世到k8s的脱颖而出,有越来越多的开源工具也在帮助开发和运维人员解 ...

  5. asp.mvc 4项目发布文件目录结构_Spring Boot项目搭建与启动

    Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不 ...

  6. Whitelabel Error Page : spring boot项目启动后,无法访问@RequestMapping标注的请求

    springboot项目创建后,会自动生成一个标注有@SpringBootApplication注解的类,直接执行该类的main方法即可启动web项目,毕竟springboot已经内置了tomcat容 ...

  7. 记一次 Spring Boot 项目启动卡住问题排查记录

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 陈凯玲 来源 | https://url.cn ...

  8. springboot 自动装配_Spring Boot 自动装配流程

    Spring Boot 自动装配流程 本文以 mybatis-spring-boot-starter 为例简单分析 Spring Boot 的自动装配流程. Spring Boot 发现自动配置类 这 ...

  9. idea jpa方法 自动提示_Spring Boot的自动配置、Commandline Runner

    点击上方☝SpringForAll社区 轻松关注!及时获取有趣有料的技术文章 来源: https://www.jianshu.com/p/846bb2d26ff8 接下来关于SpringBoot的一系 ...

最新文章

  1. 原创Python图文详解,堪称「最强文档」还有自动化办公、爬虫pdf速下!
  2. 前端怎么导出表格_前端如何导出表格数据
  3. 实时计算 Flink性能调优
  4. POJ--2449--Remmarguts#39; Date【dijkstra_heap+A*】第K短路
  5. 一步步编写操作系统 29 cpu缓存简介
  6. 深入浅出UML类图(二)
  7. 如何关闭139端口及445端口等危险端口
  8. nodejs学习笔记(上)
  9. spring中的@Bean是否一定要与@Configuration一起用
  10. r-cnn 行人检测_了解对象检测和R-CNN。
  11. 数据库mysql局部变量_MySQL内核技术之“pthead局部变量”
  12. 软件功能测试点---总结大全
  13. hdoj 1570 A C
  14. 增强型植被指数——EVI
  15. 【刷题篇】鹅厂文化衫问题
  16. 遗传算法学习笔记01
  17. Tablayout 选中字体放大 自定义
  18. BT下载会损害硬盘吗?--硬盘的工作原理,硬盘寿命
  19. 明德扬FmcAd9144 产品说明书
  20. Cathy学习Java——反射和类的加载

热门文章

  1. TensorFlow MNIST (Softmax)
  2. 介绍一下Druild,并从Twitter大数据团队分析如何应用 Druid 分析 ZB 级实时数据?
  3. Kafka删除topic Note: This will have no impact if delete.topic.enable is not【另外强烈推荐一个kafka小工具】
  4. linux网络编程--select/poll/epoll 详解
  5. 二阶差分预测后数据还原公式_携程如何基于ARIMA时序分析做业务量的预测
  6. spring三大核心学习
  7. 分布式事务——TCC 原理
  8. 02.elasticsearch-monitor使用独立的集群存储监控data
  9. 别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了
  10. 【已解决】报错:cannot be resolved to a variable