Spring Boot - ApplicationRunner && CommandLineRunner扩展接口

简介: ApplicationRunner && CommandLineRunner扩展接口

@[toc]

在这里插入图片描述


Pre

Spring Boot - 扩展接口一览

在这里插入图片描述


org.springframework.boot.CommandLineRunner

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 *
 * @author Dave Syer
 * @since 1.0.0
 * @see ApplicationRunner
 */
@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;

}

在这里插入图片描述

接口也只有一个方法:run(String... args)

如果有多个CommandLineRunner,可以利用@Order来进行排序, 按照@Order中的value值从小到大依次执行。


使用场景

  • 触发时机为整个项目启动完毕后(执行时机为容器启动完成的时候),自动执行。
  • 扩展此接口,进行启动项目之后一些业务的预处理。

源码解析

在这里插入图片描述

    /**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
    public ConfigurableApplicationContext run(String... args) {
        // 创建并启动计时监控类
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = createBootstrapContext();
        ConfigurableApplicationContext context = null;
        configureHeadlessProperty();
        // 创建所有 Spring 运行监听器并发布应用启动事件
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);
        try {
            // 处理 args 参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            
            // 准备环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            configureIgnoreBeanInfo(environment);
            
            Banner printedBanner = printBanner(environment);
            // 创建应用上下文
            context = createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            // 准备应用上下文
            prepareContext(bootstrapContext, 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);]
            // 执行所有 Runner 运行器
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            
             // 发布应用上下文就绪事件
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

继续 this.callRunners(context, applicationArguments);

核心方法 callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
        //将实现ApplicationRunner和CommandLineRunner接口的类,存储到集合中
        List<Object> runners = new ArrayList<>();
        // 从Spring容器中查找类型为ApplicationRunner的Bean
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        // 从Spring容器中查找类型为CommandLineRunner的Bean
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        
         //按照加载先后顺序排序
        AnnotationAwareOrderComparator.sort(runners);
        
        //调用执行
        for (Object runner : new LinkedHashSet<>(runners)) {
            //如果是ApplicationRunner的实例
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
             //如果是CommandLineRunner的实例
            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);
        }
    }

OK, CLEAR
在这里插入图片描述


扩展示例

ApplicationRunner

package com.artisan.bootspringextend.testextends;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;

/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/12/7 11:49
 * @mark: show me the code , change the world
 */

@Slf4j
@Configuration
public class ExtendApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info(">>>>>>>ExtendApplicationRunner#run called {}",args);

    }
}
    

----------

CommandLineRunner

package com.artisan.bootspringextend.testextends;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;

/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/12/7 9:01
 * @mark: show me the code , change the world
 */

@Slf4j
@Configuration
public class ExtendCommandLineRunner  implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info(">>>>>>>ExtendCommandLineRunner#run called {}",args);
    }
}
    

在这里插入图片描述

在这里插入图片描述

相关文章
|
2月前
|
XML Java 数据格式
探索Spring之利剑:ApplicationContext接口
本文深入介绍了Spring框架中的核心接口ApplicationContext,解释了其作为应用容器的功能,包括事件发布、国际化支持等,并通过基于XML和注解的配置示例展示了如何使用ApplicationContext管理Bean实例。
97 6
|
4月前
|
存储 算法 安全
SpringBoot 接口加密解密实现
【10月更文挑战第18天】
|
3月前
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
68 1
|
4月前
|
存储 安全 Java
|
4月前
|
监控 Java 开发者
掌握SpringBoot扩展接口:提升代码优雅度的16个技巧
【10月更文挑战第20天】 SpringBoot以其简化配置和快速开发而受到开发者的青睐。除了基本的CRUD操作外,SpringBoot还提供了丰富的扩展接口,让我们能够更灵活地定制和扩展应用。以下是16个常用的SpringBoot扩展接口,掌握它们将帮助你写出更加优雅的代码。
148 0
|
6月前
|
SQL Java 测试技术
SpringBoot单元测试快速写法问题之PorkService 接口中的 getPork 方法的作用如何解决
SpringBoot单元测试快速写法问题之PorkService 接口中的 getPork 方法的作用如何解决
|
8月前
|
监控 druid Java
Springboot用JUnit测试接口时报错Failed to determine a suitable driver class configure a DataSource: ‘url‘
Springboot用JUnit测试接口时报错Failed to determine a suitable driver class configure a DataSource: ‘url‘
153 0
|
SQL XML JSON
Spring Boot + vue-element 开发个人博客项目实战教程(九、Postman测试接口)(下)
Spring Boot + vue-element 开发个人博客项目实战教程(九、Postman测试接口)(下)
185 0
|
XML JSON 前端开发
Spring Boot + vue-element 开发个人博客项目实战教程(九、Postman测试接口)(上)
Spring Boot + vue-element 开发个人博客项目实战教程(九、Postman测试接口)(上)
188 0
|
SQL 弹性计算 前端开发
使用aliyunECS服务器+宝塔面板部署springboot后端项目并测试接口
在部署过程中遇到了很多问题,解决起来也是十分繁琐,这里写个笔记记录一下遇到的问题和思路 这里我先打算测试以下后端接口,前端代码还没有进行运行。 还没有购买域名,因为域名需要备案时间要一周所以暂时使用公网ip进行访问。