返回

SpringBoot——启动初始化数据

发布时间:2023-04-07 00:04:46 182
# java# spring# springboot# 容器# 数据

前言

在我们用 springboot 搭建项目的时候,有时候会碰到在项目启动时初始化一些操作的需求 ,针对这种需求 spring boot为我们提供了以下几种方案供我们选择:

  • ApplicationRunner 与 CommandLineRunner 接口
  • Spring容器初始化时InitializingBean接口和@PostConstruct
  • Spring的事件机制

ApplicationRunner与CommandLineRunner

我们可以实现 ApplicationRunner 或 CommandLineRunner 接口, 这两个接口工作方式相同,都只提供单一的run方法,该方法在SpringApplication.run(…)完成之前调用,我们先来看看这两个接口

@FunctionalInterface
public interface CommandLineRunner {

    /**
     * Callback used to run the bean.
     * @param args incoming main method arguments
     * @throws Exception on error
     */
    void run(String... args) throws Exception;

}

@FunctionalInterface
public interface ApplicationRunner {

    /**
     * Callback used to run the bean.
     * @param args incoming application arguments
     * @throws Exception on error
     */
    void run(ApplicationArguments args) throws Exception;

}

都只提供单一的run方法,接下来我们来看看具体的使用

ApplicationRunner

构造一个类实现ApplicationRunner接口

@Component
@Order(1)
public class ApplicationRunner1 implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("\u001B[32m[>>> startup ApplicationRunner1 <<<]");
    }
}

很简单,首先要使用@Component将实现类加入到Spring容器中,如果有多个的话通过@Order(1)进行排序,然后实现其run方法实现自己的初始化数据逻辑就可以了

CommandLineRunner

对于这两个接口而言,我们可以通过Order注解或者使用Ordered接口来指定调用顺序, @Order() 中的值越小,优先级越高

@Component
@Order(1)
public class CommandLineRunner1 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("\u001B[32m[>>> startup runner1 <<<]");
    }
}

同样需要加入到Spring容器中,CommandLineRunner的参数是最原始的参数,没有进行任何处理,ApplicationRunner的参数是ApplicationArguments,是对原始参数的进一步封装,如果有多个的话通过@Order(1)进行排序

ApplicationRunner和CommandLineRunner排序规则

  • 通过Order指定顺序
  • Order值相同ApplicationRunner的实现优先执行

源码分析

从SpringApplication.run方法的第8步callRunners开始

public ConfigurableApplicationContext run(String... args) {
    ```
    // 第八步:执行Runners
    callRunners(context, applicationArguments);
    ```
    return context;
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    //获取容器中所有的ApplicationRunner的Bean实例
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    //获取容器中所有的CommandLineRunner的Bean实例
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    //对runners集合进行排序
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            //执行ApplicationRunner的run方法
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            //执行CommandLineRunner的run方法
            callRunner((CommandLineRunner) runner, args);
        }
    }
}
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
SpringBoot——启动加载器解析 2023-04-06 20:59:52