Spring Boot 项目中的资源初始化ApplicationRunner和CommandLineRunner

       在基于SpringBoot的项目开发中会遇到这样需求:在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等。那么可以考虑使用Spring提供的两个初始化器Runner:ApplicationRunner和CommandLineRunner。实现这两个接口的 Component 会在所有 Spring Beans都初始化之后同时SpringApplication.run()之前执行,非常适合在应用程序启动之初进行一些数据初始化的工作。在Spring的官方文档中介绍如下:

一、ApplicationRunner接口

        该接口的方法会在服务启动之后被立即执行,主要用来做一些初始化的工作,但是该方法的运行是在SpringApplication.run(…​) 执行完毕之前执行:

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

@Component
@Slf4j
public class MyApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("Success to init use ApplicationRunner before startup!");
    }
}

二、CommandLineRunner接口

        CommandLineRunner跟ApplicationRunner在服务启动之后被立即执行,主要用来做一些初始化的工作,但是该方法的运行是在SpringApplication.run(…​) 执行完毕之前执行,不同的是,CommandLineRunner接口中run方法的参数为String数组,ApplicationRunner中run方法的参数为ApplicationArguments。

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

@Component
@Slf4j
public class MyCommandLineRunner implements CommandLineRunner{

    @Override
    public void run(String... args) throws Exception {
        log.info("Success to init use CommandLineRunnerbefore startup!");
    }
}

三、Runner们的执行顺序问题

       如果我们在启动容器的时候需要初始化很多资源,并且初始化资源相互之间有序,那如何保证不同的 CommandLineRunner的执行顺序呢?Spring Boot 也给出了解决方案。那就是使用 @Order 注解。

例如,项目中有两个 CommandLineRunner 的实现类:

@Component
@Order(1)
public class OrderRunner1 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The OrderRunner1 start to initialize ...");
    }
}
@Component
@Order(2)
public class OrderRunner2 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The OrderRunner2 start to initialize ...");
    }
}

通过测试会发现:添加@Order 注解的实现类会按照@Order注解内的整数顺序执行,并且@Order里面的值越小启动越早。

四、在Runner们的run方法中注意事项

对于下列几种情况,会直接影响主程序的正常启动:

1、run()函数体内不能是死循环,即如下的情况:

@Component
public class InitializeRunnerService  implements CommandLineRunner {
 
    public void run(String... strings){
        while(true){
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}

2、run()函数体内抛出未处理的异常,即如下的情况:

@Component
public class InitializeRunnerService implements CommandLineRunner {
 
    public void run(String... strings){
         throw new RuntimeException();
    }
}

五、Runner们在SpringBoot中调用的源码分析

1、首先看SpringApplication.run()入口函数:

可以看出这些Runner是在SpringBoot完成启动后且在run()函数返回前调用的。callRunners()函数源码如下:

源码中可以看到使用了AnnotationAwareOrderComparator.sort(runners)对使用@Order注解的Runner进行排序后进行分ApplicationRunner和CommandLineRunner进行调用响应的run()方法的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值