SpringBoot中CommandLineRunner和ApplicationRunner接口解析和使用

简介: SpringBoot中CommandLineRunner和ApplicationRunner接口解析和使用

用及场景

SpringBoot中提供了两个接口可以在Spring Boot启动的过程中进行一些额外的操作,比如读取配置文件、数据库操作等自定义的内容。


而这些功能的实现也非常简单,直接实现这两个接口并实现其run方法,然后将该类实例化即可。以下代码便实现了CommandLineRunner接口,并在run方法内打印了对应的日志,同时,通过@Component将其注册为Spring的一个bean。


@Component
public class LearnCommandLineRunner implements CommandLineRunner {
  @Override
  public void run(String... args) {
    System.out.println("LearnCommandLineRunner running");
  }
}

源代码

下面看一下CommandLineRunner和ApplicationRunner的源代码:

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;
}
public interface ApplicationRunner {
  /**
   * Callback used to run the bean.
   * @param args incoming application arguments
   * @throws Exception on error
   */
  void run(ApplicationArguments args) throws Exception;
}

使用源码分析

说到执行顺序,那么再进一步了解一下这两个方法是在什么时候执行的。这两个接口的实现执行的时机在于SpringApplication初始化之后,调用的run方法中被调用的。

public ConfigurableApplicationContext run(String... args) {
    // 创建 StopWatch 对象,用于统计 run 方法启动时长。
    StopWatch stopWatch = new StopWatch();
    // 启动统计。
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 配置 headless 属性。
    configureHeadlessProperty();
    // 获得 SpringApplicationRunListener 数组,
    // 该数组封装于 SpringApplicationRunListeners 对象的 listeners 中。
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 启动监听,遍历 SpringApplicationRunListener 数组每个元素,并执行。
    listeners.starting();
    try {
      //创建 ApplicationArguments 对象
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
          args);
      // 加载属性配置,包括所有的配置属性(如:application.properties 中和外部的属性配置)
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
          applicationArguments);
      configureIgnoreBeanInfo(environment);
      // 打印 Banner
      Banner printedBanner = printBanner(environment);
      // 创建容器
      context = createApplicationContext();
      // 异常报告器
      exceptionReporters = getSpringFactoriesInstances(
          SpringBootExceptionReporter.class,
          new Class[] { ConfigurableApplicationContext.class }, context);
      // 准备容器,组件对象之间进行关联
      prepareContext(context, environment, listeners, applicationArguments,
          printedBanner);
      // 初始化容器
      refreshContext(context);
      // 初始化操作之后执行,默认实现为空。
      afterRefresh(context, applicationArguments);
      // 停止时长统计
      stopWatch.stop();
      // 打印启动日志
      if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass)
            .logStarted(getApplicationLog(), stopWatch);
      }
      // 通知监听器:容器启动完成。
      listeners.started(context);
      // 调用 ApplicationRunner 和 CommandLineRunner 的运行方法。
      callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
      // 异常处理
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
    }
    try {
      // 通知监听器:容器正在运行。
      listeners.running(context);
    }
    catch (Throwable ex) {
      // 异常处理
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
    }
    return context;
  }

我们可以看到,在try方法的最后,会执行一个callRunners的方法,在此方法中会对实现这两个接口的实现类进行调用。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
      if (runner instanceof ApplicationRunner) {
        callRunner((ApplicationRunner) runner, args);
      }
      if (runner instanceof CommandLineRunner) {
        callRunner((CommandLineRunner) runner, args);
      }
    }
  }
  private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
    try {
      (runner).run(args);
    }
    catch (Exception ex) {
      throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
    }
  }
  private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
    try {
      (runner).run(args.getSourceArgs());
    }
    catch (Exception ex) {
      throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
    }
  }

通过以上代码,我们也就了解到这两个接口的实现类的执行时机了。


目录
相关文章
|
8月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
1133 3
|
8月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2666 0
|
7月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
7月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
551 3
|
11月前
|
算法 网络协议 Java
Spring Boot 的接口限流算法
本文介绍了高并发系统中流量控制的重要性及常见的限流算法。首先讲解了简单的计数器法,其通过设置时间窗口内的请求数限制来控制流量,但存在临界问题。接着介绍了滑动窗口算法,通过将时间窗口划分为多个格子,提高了统计精度并缓解了临界问题。随后详细描述了漏桶算法和令牌桶算法,前者以固定速率处理请求,后者允许一定程度的流量突发,更符合实际需求。最后对比了各算法的特点与适用场景,指出选择合适的算法需根据具体情况进行分析。
962 56
Spring Boot 的接口限流算法
|
8月前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
1564 1
|
10月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
10月前
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
1798 5
|
10月前
|
Java 关系型数据库 数据库连接
Spring Boot项目集成MyBatis Plus操作PostgreSQL全解析
集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步骤与 MyBatis 类似,只不过在 MyBatis Plus 中提供了更多的便利功能,如自动生成 SQL、分页查询、Wrapper 查询等。
981 2

推荐镜像

更多
  • DNS