在Spring Boot应用启动之后立刻执行一段逻辑

码农小胖哥:如何在Spring Boot应用启动之后立刻执行一段逻辑

项目启动后立马执行一些逻辑。比如简单的缓存预热,或者上线后的广播之类等等。如果你使用 Spring Boot 框架的话就可以借助其提供的接口CommandLineRunner和 ApplicationRunner来实现。

1、CommandLineRunner

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

优先执行:

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component; /**
* 优先级最高
* 该类期望在springboot 启动后第一顺位执行
**/
@Slf4j
@Component
public 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;
}
}

第二顺序执行:

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component; /**
* 优先级低于{@code HighOrderCommandLineRunner}
**/
@Slf4j
@Component
public 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 highOrderRunner
2020-05-30 23:11:03.706 INFO 11976 --- [ main] c.f.LowOrderCommandLineRunner : i am lowOrderRunner

2、ApplicationRunner

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

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; /**
* 优先级最低
**/
@Slf4j
@Component
public class DefaultApplicationRunner implements ApplicationRunner, Ordered {
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("i am applicationRunner");
Set<String> optionNames = args.getOptionNames();
log.info("optionNames = " + optionNames);
String[] sourceArgs = args.getSourceArgs();
log.info("sourceArgs = " + Arrays.toString(sourceArgs));
List<String> nonOptionArgs = args.getNonOptionArgs();
log.info("nonOptionArgs = " + nonOptionArgs);
List<String> optionValues = args.getOptionValues("foo");
log.info("optionValues = " + optionValues);
} @Override
public 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 highOrderRunner
2020-06-01 13:02:39.423 INFO 19032 --- [ main] c.f.LowOrderCommandLineRunner : i am lowOrderRunner
2020-06-01 13:02:39.423 INFO 19032 --- [ main] c.f.DefaultApplicationRunner : i am applicationRunner
2020-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注解所代替。

3、传递参数

Spring Boot应用启动时是可以接受参数的,换句话说也就是Spring Boot的main方法是可以接受参数的。这些参数通过命令行 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应用启动之后立刻执行一段逻辑的更多相关文章

  1. 如何在Spring Boot应用启动之后立刻执行一段逻辑

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

  2. spring boot无法启动,或者正常启动之后无法访问报404的解决办法

    以前用spring boot都是用idea的自动创建,或者是用的Jhipster创建的,就没有深究怎么去搭建.但是今天晚上心血来潮,想自己搭一个demo来整合一些技术,于是就花一点时间来手动搭.因为今 ...

  3. spring boot容器启动详解

    目录 一.前言 二.容器启动 三.总结 =======正文分割线====== 一.前言 spring cloud大行其道的当下,如果不了解基本原理那么是很纠结的(看见的都是约定大于配置,但是原理呢?为 ...

  4. 让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean

    让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean 问题描述 实现思路 思路一 [不符合要求] 思路二[满足要求] 思路三[未试验] 问题描述 目前我工作环境下,后端主要的框架 ...

  5. Spring boot自定义启动字符画(banner)

    spring boot项目启动时会打印spring boot的ANSI字符画,可以进行自定义. 如何自定义 实现方式非常简单,我们只需要在Spring Boot工程的/src/main/resourc ...

  6. spring boot 项目启动无任何反应

    遇到的问题 spring boot项目启动后无任何报错,ps有进程,nohub无日志 定位 更换jar包,问题依然存在,将jar包放到其他服务器,运行正常,排除打包问题 同服务器其他系统运行正常,但停 ...

  7. Spring Boot定制启动图案

    启动图案 Spring Boot在启动的时候会显示一个默认的Spring的图案,对应的类为SpringBootBanner. . ____ _ __ _ _ /\\ / ___'_ __ _ _(_) ...

  8. Spring Boot 设置启动时banner

    Spring Boot项目再启动的时候默认会在控制台输出一个字符banner图案,如下图: 我们可以通过下面的方法关闭启动时显示字符banner图案: 关闭banner方法一: public stat ...

  9. spring boot应用启动原理分析

    spring boot quick start 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个We ...

随机推荐

  1. Java学习日报7.16

    void StudentManage::Sort() //排序功能{ StudentInfo *h,*curr,*temp,*last; h=head; for(int j=0;j<n;j++) ...

  2. codeforces 1438D,思路非常非常巧妙的构造题

    大家好,欢迎来到codeforces专题. 今天选择的问题是contest1438的D题,全场通过人数为1325人.一般在codeforces当中千人通过的题难度都不算太高,但是这题有点例外,虽然没有 ...

  3. Vue - MVVM模式及优点

    MVVM模式 视图层和数据层的双向绑定,让我们无需再去关心DOM操作的事情,更多的精力放在数据和业务逻辑上去 MVVM是Model-View-ViewModel的缩写.MVVM是一种设计思想. Mod ...

  4. 一台PC端安装多店仓信息的删除

    如图所示,安装了多店仓,想要删除其中莫一店仓信息! 步骤一:先找到对应目录,一般默认的目录为C:\Users\xxxx\AppData\Roaming\WebPos2.0\bosnatweiniman ...

  5. 网易163 docker镜像

    $ sudo echo "DOCKER_OPTS=\"--registry-mirror=http://hub-mirror.c.163.com\"" > ...

  6. 常用 .gitignore 模板

    前言 每次建项目的时候可以直接复制了,也算是方便自己,以后发现少的会更新 正文 作用 git提交时忽略文件 文件名 .gitignore Python # Byte-compiled / optimi ...

  7. Python模块化编程与装饰器

    Python的模块化编程 我们首先以一个例子来介绍模块化编程的应用场景,有这样一个名为requirements.py的python3文件,其中两个函数的作用是分别以不同的顺序来打印一个字符串: # r ...

  8. 🎉 Element UI for Vue 3.0 来了!

    第一个使用 TypeScript + Vue 3.0 Composition API 重构的组件库 Element Plus 发布了 ~ 2016 年 3 月 13 日 Element 悄然诞生,经历 ...

  9. 2021年正确的Android逆向开发学习之路

    2021年正确的Android逆向开发学习之路 说明 文章首发于HURUWO的博客小站,本平台做同步备份发布.如有浏览或访问异常或者相关疑问可前往原博客下评论浏览. 原文链接 2021年正确的Andr ...

  10. 单元测试:单元测试中的mock

    公司要求提升单元测试的质量,提高代码的分支覆盖率和行覆盖率,安排我研究单元测试,指定方案分享并在开发部普及开.整理完资料后,同步一下到博客. 单元测试中的mock的目的 mock的主要目的是让单元测试 ...