自定义 SpringBoot 启动方法的六种方式(上)

2022-03-15 21:43:14   最后更新: 2022-03-15 21:43:14   访问数量:128




 

去年我写了一篇文章,记录了一次线上性能的优化:

 

在 filter 中使用错误的方法获取 ip 地址造成性能问题排查

 

最终,得到结论:

 

  • 本机 ip 等固定信息,不要在 filter 中获取,而要改为 spring 启动时获取一次,以避免性能损失。

 

那么,怎么让 spring 框架在启动时执行这些固定的代码呢?事实上,这里面还有不少学问呢。

 

本文,我们就来详细介绍配置 SpringBoot 启动时动作的六种方法。

 

 

 

 

2.1 获知启动事件

 

有时,你需要知道项目什么时候发生了启动,所以你可能要在 SpringBoot 启动前打印一些必要的日志。

 

不仅如此,有的时候你还需要对启动的事件做一些关联性的工作,例如同样去重启另一个项目等,那这时你可能需要接入消息队列等组件来传递启动消息。

 

2.2 处理静态资源的初始化操作

 

很多静态资源,例如数据库、文件、缓存、索引等等静态资源是需要在每次项目启动时做一些初始化操作。

 

最简单的,我们上面提到的上文获取 IP 地址的操作就属于这类静态资源之一。

 

2.3 启动某些守护进程

 

某些后台运行的监控程序、数据统计程序可能需要进行一些启动或是初始化操作。

 

2.4 项目需要根据启动参数的不同具有不同的行为

 

项目需要根据启动参数产生不同的行为也是一个常见的需求,例如可能需要通过一个参数临时开启 DEBUG 模式,或是将某个环境变量转换为参数传入你的程序中。

 

 

下面六种方式都可以让 SpringBoot 在启动时运行自定义的代码:

 

  1. 实现 CommandLineRunner 接口
  2. 实现 ApplicationRunner 接口
  3. 通过 EventListener 监听启动事件
  4. 通过 @Postconstruct 注解
  5. 实现 InitializingBean 接口
  6. 通过 @Bean 注解

 

下面我们就来一一介绍一下。

 

 

4.1 CommandLineRunner 接口

 

org.springframework.boot.CommandLineRunner 是 SpringBoot 提供的一个接口,你可以通过实现它在项目启动时添加代码执行。

 

只要我们的 bean 实现了这个接口,并覆写了 run 方法,SpringBoot 启动时就会自动调用 run 方法。

 

4.2 示例

 

@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); } } }

 

 

或者通过匿名类的方式返回一个实例:

 

@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); } }; } }

 

 

通过 maven 命令运行:

 

mvn spring-boot:run -Dspring-boot.run.arguments="–status=running"

 

或者通过 java 命令运行:

 

mvn package java -jar target/<FILENAME.JAR HERE> --status=running

 

打印出了:

 

In CommandLineRunnerImpl status=running

 

  • 需要注意的是,如果 run 方法中抛出了异常,会中止项目的启动。

 

 

5.1 ApplicationRunner 接口

 

上述示例的打印结果可以看到,status=running 是作为一个 String 参数一起传入到 run 方法中的,这对于我们来说经常会感到很不方便,通常我们希望 status 和 running 分别作为 key、value 来被我们的程序处理。

 

SpringBoot 1.3 版本加入的 ApplicationRunner 接口可以十分方便地传递解析后的参数。

 

与 CommandLineRunner 不同,ApplicationRunner 的 run 方法接收的参数是一个 ApplicationArguments 类的对象。

 

ApplicationArguments 类包含以下方法:

 

方法 描述
----------------------------------------------- -----------------------------------
String.. GetSourceArgs() 返回未经处理的参数列表
Set<String> getOptionNames() 返回由所有参数的 key 组成的 Set
List<String> getNonOptionArgs() 传递未经处理的不存在 key 的参数列表
boolean containsOption(String name) 判断指定 key 是否存在
List<String> getOptionValues(String name) 通过 key 查询对应的 value

5.2 示例

 

@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:[] } } }

 

 

通过参数 status=running --mood=happy 10 --20 参数调用,打印出了:

 

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 接口相同,一旦 run 方法抛出异常,项目的启动也会随之中止。

 

 

本文,我们介绍了六种 SpringBoot 启动时运行代码的方法,并且详细介绍了其中两个可以获取和处理 spring 启动参数的方法。

 

还有四种各具特色的添加启动项的方式,敬请期待下一篇文章的介绍吧。

 

 

https://stacktraceguru.com/springboot/run-method-on-startup

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 

Spring 从入门到实战






java      技术贴      springboot      boot     


京ICP备2021035038号