SpringBoot中CommandLineRunner详解(含源码)

news2025/1/15 6:23:08

文章目录

      • 前言
      • 实例
        • 导入库
        • application.yaml
        • Runner
        • SpringBootCommandLineRunnerApplication
        • 执行结果
      • 先后顺序示例
        • OrderRunner1
        • OrderRunner2
        • 执行结果
      • 通常用法
        • 加载初始化数据
          • 示例
        • 启动后打印应用信息
          • 示例
        • 启动异步任务
          • 示例
        • 接口健康检查
          • 示例
        • 外部服务调用
          • 示例
        • 参数校验
          • 示例
        • 动态设置配置
          • 示例
            • application.yaml
            • MyConfig
            • ConfigRunner
        • 启动阻塞
      • 总结
      • 源码获取
      • 写在最后

579a429daf314744b995f37351b46548

前言

Spring Boot的CommandLineRunner接口是一个函数式接口,用于在Spring Boot应用程序启动后执行一些初始化操作。它提供了一个run方法,该方法在应用程序启动后被调用。

使用CommandLineRunner接口,可以在应用程序启动后执行一些必要的初始化操作,例如加载配置文件、初始化数据库连接、创建默认数据等。可以通过实现CommandLineRunner接口,并重写run方法来定义自己的初始化逻辑。


实例

导入库
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.0</version>
</parent>

<groupId>org.example</groupId>
<artifactId>springboot-CommandLineRunner</artifactId>
<version>1.0-SNAPSHOT</version>

<name>Spring Boot banner</name>
<description>Spring Boot and commandLineRunner</description>

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>
application.yaml
server:
  port: 8080

spring:
  profiles:
    active: dev
Runner
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class Runner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("The Runner start to initialize ...");
    }
}
SpringBootCommandLineRunnerApplication
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@Slf4j
public class SpringBootCommandLineRunnerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootCommandLineRunnerApplication.class, args);
        log.info("The service to end");
    }
}
执行结果

image-20231030003209704

在上面的示例中,我们创建了一个名为MyCommandLineRunner的类,并实现了CommandLineRunner接口。在run方法中,我们可以编写需要在应用程序启动后执行的初始化逻辑。

需要注意的是,实现CommandLineRunner接口的类需要被Spring容器扫描到,可以使用@Component注解或其他方式将其注册为Spring Bean。

先后顺序示例

可以通过@Order()来设置Runner的先后顺序,在上面例子的基础上增加

OrderRunner1
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
@Slf4j
public class OrderRunner1 implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("The OrderRunner1 start to initialize ...");
    }
}
OrderRunner2
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(2)
@Slf4j
public class OrderRunner2 implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("The OrderRunner2 start to initialize ...");
    }
}
执行结果

image-20231030003553969


通常用法

image-20231030004258880

加载初始化数据

可以实现CommandLineRunner接口,在run方法中加载一些初始化数据到数据库等。适合做一些数据预加载工作。

示例
@Component
public class DataInitializer implements CommandLineRunner {

    @Autowired
    private UserRepository userRepository;

    @Override
    public void run(String... args) throws Exception {
        
        // 创建初始用户
        User admin = new User("admin", "123456");
        userRepository.save(admin);

        User normalUser = new User("user", "123456");
        userRepository.save(normalUser);
        
        System.out.println("数据加载完毕!");
    }
}

这里创建了一个 DataInitializer 类,实现 CommandLineRunner 接口。在 run() 方法中,我们注入了 UserRepository,然后创建了两个用户对象保存到数据库中。这个类会在 Spring Boot 应用启动完成后执行,从而实现了数据预加载的效果。通过 CommandLineRunner,我们可以灵活地在 Spring Boot 启动时进行一些初始化操作,如预先加载测试数据、插入管理员账户等,很好地增强了应用的功能。

假设我们有一个User模型和用户Repository,需要在Spring Boot启动时预加载几个用户数据,可以这样使用CommandLineRunner:

@Component
public class DataInitializer implements CommandLineRunner {

    @Autowired
    private UserRepository userRepository;

    @Override
    public void run(String... args) throws Exception {
        
        // 清除所有数据
        userRepository.deleteAll(); 
        
        // 创建几个用户
        User user1 = new User("John", "john@example.com");
        User user2 = new User("Mary", "mary@example.com");
        
        userRepository.save(user1);
        userRepository.save(user2);
        
        // 打印已保存用户数
        System.out.println("Number of users saved: " + userRepository.count());
    }

}

这里我们实现了CommandLineRunner接口,然后注入UserRepository bean。在run方法中,首先清空所有数据,然后创建两个用户对象并保存,最后打印已保存的用户数。这样在Spring Boot应用启动完成后,就会自动执行run方法,预加载指定的用户数据。

启动后打印应用信息

可以打印出一些应用启动信息,如启动端口、运行环境信息等,用于确认应用配置。

示例
@Component
@Slf4j
public class AppInfoPrinter implements CommandLineRunner {

    @Autowired
    private Environment environment;
    @Override
    public void run(String... args) throws Exception {

        log.info("========= 打印启动信息 =========");
        // 打印应用端口
        log.info(("端口号: " + environment.getProperty("server.port")));
        // 打印当前环境
        log.info("当前环境: " + environment.getProperty("spring.profiles.active"));
        // 打印JDK版本
        log.info("JDK 版本: " + System.getProperty("java.version"));
        log.info("========= 打印启动信息结束 =========");

    }

}

执行打印结果

image-20231030011038160

启动异步任务

可以使用多线程启动一些异步任务,进行后台数据处理等复杂业务逻辑。

示例
@Component
@Slf4j
public class AsyncTaskRunner implements CommandLineRunner {

    @Autowired
    private AsyncTaskService asyncTaskService;

    @Override
    public void run(String... args) throws Exception {
        log.info("========= 执行任务 =========");
        // 在新线程中执行任务
        new Thread(() -> {
            asyncTaskService.doTaskOne();
            asyncTaskService.doTaskTwo();
            asyncTaskService.doTaskThree();
        }).start();
    }

}

@Service
@Slf4j
class AsyncTaskService {

    public void doTaskOne() {
        log.info("执行任务1");
    }

    public void doTaskTwo() {
        log.info("执行任务2");
    }

    public void doTaskThree() {
        log.info("执行任务3");
    }
}

执行结果

[           main] org.example.runner.AsyncTaskRunner       : ========= 执行任务 =========
[       Thread-1] org.example.runner.AsyncTaskService      : 执行任务1
[       Thread-1] org.example.runner.AsyncTaskService      : 执行任务2
[       Thread-1] org.example.runner.AsyncTaskService      : 执行任务3
接口健康检查

可以调用并验证依赖服务的健康状态,如果不正常可以终止Spring Boot启动。

示例
@Component
@Slf4j
public class HealthCheckRunner implements CommandLineRunner {

    @Autowired
    private DatabaseService databaseService;

    @Autowired
    private MessageQueueService messageQueueService;

    @Override
    public void run(String... args) throws Exception {

        if(!databaseService.isConnected()) {
            log.error("数据库服务不可用,退出应用!");
            System.exit(1);
        }

        if(!messageQueueService.isConnected()) {
            log.error("消息队列服务不可用,退出应用!");
            System.exit(1);
        }

        log.info("所有服务正常,应用启动。");

    }
}

这里我们注入两个依赖服务 DatabaseService 和 MessageQueueService。在run方法中,调用它们的健康检查方法,如果任何一个服务不可用,则直接调用System.exit(1)退出Spring Boot应用启动。

外部服务调用

可以在启动时调用外部服务,进行验证、数据同步等操作。

示例
@Component
public class OtherServiceCheckRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        // 健康检查的URL
        String healthCheckUrl = "http://localhost:8080/actuator/health";

        RestTemplate restTemplate = new RestTemplate();
        // 发送GET请求进行健康检查
        String response = restTemplate.getForObject(healthCheckUrl, String.class);

        // 根据响应判断健康状态
        if (response.contains("\"status\":\"UP\"")) {
            System.out.println("Application is healthy");
        } else {
            System.out.println("Application is not healthy");
        }
    }
}
参数校验

可以对输入的运行参数做校验,如果不满足条件可以终止Spring Boot启动。

示例
@Component
@Slf4j
public class ParameterValidator implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        // 校验参数1
        if(args.length < 2) {
            log.error("参数不正确,请传入至少2个参数!");
            System.exit(1);
        }

        // 校验参数2是否为数字
        if(!args[1].matches("\\d+")) {
            log.error("第二个参数必须是数字!");
            System.exit(1);
        }

        // 校验通过,应用继续启动
        log.info("参数校验通过,应用启动中...");
    }
}

在run方法中,我们可以对main方法输入的参数args进行自定义校验:

  • 检查参数数量
  • 校验参数类型

如果参数不满足需求,可以直接调用System.exit(1)来终止Spring Boot的启动。这样就可以在应用启动前验证参数的正确性,避免应用启动后发生未知错误。

动态设置配置

可以根据运行参数等条件动态设置Spring Boot的配置,实现不同环境的适配。

示例
application.yaml
myconfig:
  foo: 十五
  bar: 1
MyConfig
@Component
@Data
@ConfigurationProperties(prefix = "myconfig")
public class MyConfig {
    private String foo;
    private int bar;

// getter和setter方法省略

    @Override
    public String toString() {
        return "MyConfig{" +
                "foo='" + foo + '\'' +
                ", bar=" + bar +
                '}';
    }
}
ConfigRunner
@Component
@EnableConfigurationProperties(MyConfig.class)
public class ConfigRunner implements CommandLineRunner {

    @Autowired
    private MyConfig myConfig;

    @Override
    public void run(String... args) throws Exception {
// 打印当前配置
        System.out.println("Current config: " + myConfig);

// 动态设置配置
        myConfig.setFoo("new value");
        myConfig.setBar(100);

// 打印更新后的配置
        System.out.println("Updated config: " + myConfig);
    }
}
启动阻塞

可以使应用启动后阻塞住主线程,防止main方法直接退出,从而保持Spring Boot应用运行。

示例

@Component
@Slf4j
public class StartBlocker implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        // 加载提示信息
        log.info("正在等待管理员授权...");

        // 等待授权,阻塞启动流程
        waitAuth();

        // 授权完成后继续启动
        log.info("管理员已授权,应用启动中...");
    }

    private void waitAuth() {
        // 死循环模拟等待管理员操作授权
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;
            }
        }
    }

}

总结

通过 CommandLineRunner,我们可以深度控制 Spring Boot 应用的启动流程,在应用启动阶段增强各种自定义逻辑。是 Spring Boot 提供的一个很实用的扩展点。


源码获取

如果需要完整源码请关注公众号"架构殿堂" ,回复 "SpringBoot+CommandLineRunner"即可获得


写在最后

感谢您的支持和鼓励! 😊🙏

如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot, spring cloud等系列文章,一系列干货随时送达!

csdn-end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1149336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV学习笔记

OpenCV基础 threshold函数的使用 https://blog.csdn.net/u012566751/article/details/77046445 图像的二值化就是将图像上的像素点的灰度值设置为0或255&#xff0c;这样将使整个图像呈现出明显的黑白效果。在数字图像处理中&#xff0c;二值图像占有非常重要的地位&#xff0…

四个制作PPT的小技巧

制作PPT已经很麻烦了&#xff0c;学习一些小技巧可以帮助我们省时省力吧&#xff01; 技巧一&#xff1a;自动更新日期和时间 当我们给幻灯片添加了页脚并且是时间日期&#xff0c;可以通过设置达到自动更新&#xff0c;这样我们就不需要每次修改的时候都要手动更新日期和时间…

电商API接口中关于品牌详情/商品评论/视频/店铺链接等电商数据采集实例

单个品牌详情API接口 接口亮点&#xff1a;1.品牌商品&#xff0c;质量保障 2.高性价比商品&#xff0c;转化高 接口说明&#xff1a;该接口返回某个具体品牌的详细信息和推荐商品 使用场景&#xff1a;展示单个品牌相关信息以及品牌商品 商品评论API接口 接口亮点&…

C语言KR圣经笔记 2.8自增和自减 2.9位运算 2.10赋值

2.8 自增和自减操作符 C提供了两个不同寻常的操作符&#xff0c;用于对变量进行自增和自减。自增操作符对操作数加上1&#xff0c;而自减操作符 -- 对操作数减去1。我们已经频繁使用 对变量进行自增&#xff0c;如&#xff1a; if (c \n)nl; 不寻常之处在于 和 -- 既能用作…

接触式静电压测量仪的用途和操作方法

接触式静电压测量仪是一种用于测量静电电荷的仪器&#xff0c;主要用于工业生产和科学研究领域。它可以测量静电电压、静电场强、静电电荷等参数&#xff0c;对于静电控制和环境监测等方面具有重要的作用。 接触式静电压测量仪的操作方法如下&#xff1a; 接通电源&#xff1a;…

【Java系列】HashSet

HashSet 介绍添加元素判断元素是否存在删除元素删除集合中所有元素可以使用 clear 方法&#xff1a;计算大小迭代 HashSet 系列文章版本记录 介绍 HashSet 基于 HashMap 来实现的&#xff0c;是一个不允许有重复元素的集合。 HashSet 允许有 null 值。 HashSet 是无序的&#x…

PHP | php入门知识(if、switch、数组、数组排序、超级全局变量)

文章目录 一、php条件语句&#xff08;if、switch&#xff09;1. if语句2. if...else语句3. if...elseif...else语句4. switch语句 二、数组1&#xff09;数值数组1. 创建数值数组的两种方法&#xff1a;2. 获取数组的长度&#xff08;count()函数&#xff09;3. 遍历数值数组&…

港大联合百度开源通用图大模型GraphGPT:让大语言模型读懂图数据

导读 图神经网络&#xff08;GNN&#xff09;已成为处理和学习图数据的强大工具&#xff0c;在社交网络分析、推荐系统、智慧城市和生物信息等多个领域带来了革命性的进展。图神经网络的核心优势在于其揭示图数据中复杂关联性的能力。通过消息传递和信息聚合&#xff0c;图神经…

Leo赠书活动-04期 【国家数据局正式揭牌,数据专业融合型人才迎来发展良机 】文末送书5本

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

数据防泄密软件排行榜(10大数据防泄密软件推荐)

众所周知&#xff0c;公司中往往由于员工离职而出现泄密的情况&#xff0c;比如公司的财务资料、客户资料以及数据资料等&#xff0c;员工在跳槽的时候将这些带走&#xff0c;管理者无从考证导致部门甚至企业出现亏损的情况。 数据泄密一旦发生&#xff0c;企业在查证追责时就有…

有了这本书学习递归算法不再那么难

递归是一种编程技术&#xff0c;能够产生相当优雅的代码&#xff0c;但它也经常会把写代码和看代码的程序员给弄糊涂。这并不是说程序员可以或者应该忽略递归。尽管大家都知道递归比较难&#xff0c;但是这是计算机科学领域的一个重要话题&#xff0c;它能让你敏锐地观察到编程…

【linux进程(七)】程序地址空间深度剖析

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; 程序地址空间 1. 前言2. 什么…

中国卖家的出路:TikTok电商重塑东南亚市场

2023年10月4日&#xff0c;印尼政府发布了一则重要公告&#xff0c;宣布不再允许社交媒体作为商品销售平台。这一决策直接影响了TikTok在印尼的电商业务&#xff0c;迫使该平台关闭了其印尼市场的电商运营。 对于TikTok电商而言&#xff0c;印尼市场一直占据着重要地位&#x…

机器视觉工程师们,人的命运大多数连在一起

看着鱼池里的小鱼&#xff0c;很是治愈。自己的往后的生活还要继续。 有次出差&#xff0c;和工作经验13年机器视觉工程师&#xff0c;他用手指着流水线上的操作工说&#xff0c;他们失业&#xff0c;去干什么&#xff0c;回家种田吗&#xff1f;都机械化种田&#xff0c;回家…

程序员为啥要做副业(02)-中指备用金

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

table 部分列宽度固定,剩余列宽度等分

table 固定列固定宽度&#xff0c;剩余列给最小宽度 <thead><tr><th rowspan"2" style"width:100px">序号</th><th rowspan"2" style"width:120px">姓名</th><th v-for"date in dates&q…

如何实现可靠的数据调度同步,数据同步方案看一下!

随着企业规模不断扩大&#xff0c;分支机构越来越多&#xff0c;跨区域跨国的集团越来越多&#xff0c;越来越多的企业要求内部各种业务数据在服务器、数据中心甚至云上&#xff0c;能够进行实时的调度和同步&#xff0c;从而需要部署一套数据同步方案&#xff0c;实现服务器与…

DC电源模块如何承受超负荷电流的能力

BOSHIDA DC电源模块如何承受超负荷电流的能力 DC电源模块是现代电子设备中必不可少的部件&#xff0c;它们通常被用来将交流电转换为稳定的直流电&#xff0c;为电子设备提供所需的电力。在某些情况下&#xff0c;DC电源模块可能会遇到超负荷电流的情况&#xff0c;如启动过程…

CleanMyMacXMac4.14.4版本系统优化工具

CleanMyMac是macOS上不可或缺的清理工具&#xff0c;它的作用非常强大&#xff0c;可以帮助用户清理系统、照片、邮件、iTunes垃圾&#xff0c;甚至是隐私数据。以下是CleanMyMac的主要功能和特点&#xff1a; 首先&#xff0c;CleanMyMac可以帮助清理系统垃圾&#xff0c;包括…

Pyqt5 List Widget 用户自定义添加/删除字段

添加和删除字段的逻辑 在窗口上显示一个list widget的窗口&#xff0c;还有一个添加字段的按钮 点击添加字段会弹出一个输入框&#xff0c;将内容作为一个item添加到list widget中 点击对应的已添加的字段&#xff0c;即会显示删除按钮&#xff0c;点击即可删除该字段 效果…