添加 SpringBoot 自定义启动代码的六种方式(上)

1. 引言

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

你知道 java 获取本地 ip 地址有两种方法吗?讲讲隐藏在他们背后的哪些坑

最终,得到结论:

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

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

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

2. 什么代码需要在 SpringBoot 启动时运行

2.1 获知启动事件

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

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

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

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

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

2.3 启动某些守护进程

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

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

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

3. 六种 SpringBoot 启动时运行代码的方法

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

  1. 实现 CommandLineRunner 接口

  2. 实现 ApplicationRunner 接口

  3. 通过 EventListener 监听启动事件

  4. 通过 @Postconstruct 注解

  5. 实现 InitializingBean 接口

  6. 通过 @Bean 注解

下面我们就来一一介绍一下,受限于文章长度,本文我们将只介绍其中的前两个,后面的四个敬请期待下文。

4. 实现 CommandLineRunner 接口

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. 实现 ApplicationRunner 接口

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 Calledarg: status=runningarg: –mood=happarg: 10arg: –20NonOptionArgs: [status=running , 10]OptionNames: [mood, 20]Printing key and value in loop:key: moodval: [happy]key: 20val: []

与 CommandLineRunner 接口相同,一旦 run 方法抛出异常,项目的启动也会随之中止。

6. 结语

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

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

附录 – 参考资料

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

添加 SpringBoot 自定义启动代码的六种方式(上)》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:https://www.bookhoes.com/4873.html