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);
    }
}
    

在这里插入图片描述

在这里插入图片描述

相关文章
|
9天前
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
26 1
|
15天前
|
存储 安全 Java
|
15天前
|
存储 算法 安全
SpringBoot 接口加密解密实现
【10月更文挑战第18天】
|
13天前
|
监控 Java 开发者
掌握SpringBoot扩展接口:提升代码优雅度的16个技巧
【10月更文挑战第20天】 SpringBoot以其简化配置和快速开发而受到开发者的青睐。除了基本的CRUD操作外,SpringBoot还提供了丰富的扩展接口,让我们能够更灵活地定制和扩展应用。以下是16个常用的SpringBoot扩展接口,掌握它们将帮助你写出更加优雅的代码。
35 0
|
29天前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
138 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
26天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
137 2
|
3月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
26天前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
44 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
4月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。