详解ApplicationRunner和CommandLineRunner

一、前言

springBoot框架项目,有时候有预加载数据需求——提前加载到缓存中或类的属性中,并且希望执行操作的时间是在容器启动末尾时间执行操作。比如笔者工作中遇到了一个预加载redis中的缓存数据,加载为java对象。针对这种场景,SpringBoot提供了两个接口,分别是CommandLineRunner和ApplicationRunner。两个接口都在spring-boot的jar包中(spring-boot的jar包依附关系:spring-boot<-spring-boot-starter<-spring-boot-starter-web),项目只需要依赖spring-boot-starter-web的jar便可使用。

当程序启动时,我们传给 main() 方法的参数可以被实现 CommandLineRunner 和 ApplicationRunner 接口的类的 run() 方法访问,即可接收启动服务时传过来的参数,自动执行各自接口中的run方法,完成一些初始化动作。我们可以创建多个实现 CommandLineRunner 和 ApplicationRunner 接口的类。为了使他们按一定顺序执行,可以使用 @Order 注解或实现 Ordered 接口。

二、ApplicationRunner和CommandLineRunner的比较

共同点

  1. 自动执行: 只需实现相应的接口并将其作为一个Bean注册到Spring容器中(通常是通过@Component注解),Spring Boot在应用启动后会自动调用这些接口的run方法。

  2. 访问命令行参数: 两个接口的run方法都接收一个ApplicationArguments对象,该对象提供了访问启动时传递给应用的命令行参数的方法。

ApplicationRunner

  1. 更细粒度的参数处理: 相比于CommandLineRunner,ApplicationRunner提供了更详细的参数处理API,如区分非选项参数(nonOptionArgs)和选项参数(getOptionNames、getOptionValues),这使得在处理复杂命令行参数时更加灵活方便。

  2. 用途: 当你需要根据不同的命令行参数执行不同的初始化逻辑时,ApplicationRunner提供了更丰富的功能来解析和处理这些参数。

CommandLineRunner

  1. 简单直接: 如果你的需求只是简单地执行一些初始化逻辑,且不需要对命令行参数做精细处理,CommandLineRunner是一个更简洁的选择。它的run方法直接接受ApplicationArguments,但通常用于较为基本的参数检查或打印帮助信息。

  2. 用途: 对于那些只需要知道是否有参数被传入,或者参数数量,而不需要详细解析每个参数的应用场景,使用CommandLineRunner会更加直接。

选择ApplicationRunner还是CommandLineRunner取决于你的具体需求:如果你需要对命令行参数进行更细致的操作和解析,选择ApplicationRunner。如果你的需求简单,仅需执行一些基础的启动任务,且对命令行参数的处理不复杂,则CommandLineRunner足矣。两者都非常适用于执行应用程序启动初期的初始化或设置任务。下面对这两个接口做详细解析和案例分析。

三、CommandLineRunner接口

源码如下:

@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;

}

从源码看到参数为String数组,即可以传多个参数,以数组形式接收。

自定义一个类实现 CommandLineRunner 接口:

package com.hulei.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyCommandLineRunner.class);

    @Override
    public void run(String... args) {
        String strArgs = String.join("|", args);
        logger.info("Application started with arguments:{}", strArgs);
    }
}

笔者使用的是IDEA工具(IDEA必须要学会使用,如果不会,我认为是极其不专业的java开发),直接右击package打包

在这里插入图片描述
在这里插入图片描述
现在选择使用命令java -jar的方式启动这个jar包,可以找到项目所在目录,直接cmd进入这个target下执行命令:

java -jar Add-WaterMark-0.0.1-SNAPSHOT.jar data1 data2 data2

其中data1、data2、data3就是启动时输入的参数,笔者这里直接使用IDEA的teminal控制台启动了,但是要先把Terminal的Shell path设置成cmd.exe路径。

在这里插入图片描述

在上面package打包后,打开一个terminal终端,输入以下命令

cd target
java -jar Add-WaterMark-0.0.1-SNAPSHOT.jar data1 data2 data3

在这里插入图片描述
按下Enter回车执行,执行结果如下:

在这里插入图片描述
控制台并没有出现 MyCommandLineRunner类中打印参数的信息

logger.info("MyCommandLineRunner started with arguments:{}", strArgs);

经过排查发现笔者把目录建错了,没有建在启动类 AddWaterMarkApplication所在的直接根目录watermark下,导致无法扫描到 MyCommandLineRunner类,因为**@SpringBootApplication**默认只扫描定义了该注解的类所在的包及其所有子包下的组件。
在这里插入图片描述
做法一是把runner文件目录转移到watermark下,做法二如下:
在@SpringBootApplication注解中加入基础包扫描,手动写入需要扫描的包路径
在这里插入图片描述

此时再关闭terminal终端,重新package打包,重新打开terminal终端执行启动命令

看到MyCommandLineRunner中的run方法成功执行了,打印出我们启动时添加的启动参数

在这里插入图片描述

四、ApplicationRunner接口

源码如下

@FunctionalInterface
public interface ApplicationRunner extends Runner {

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

}```

自定义一个类MyApplicationRunner实现ApplicationRunner接口

```java
package com.hulei.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;


@Component
public class MyApplicationRunner implements ApplicationRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyApplicationRunner.class);

    @Override
    public void run(ApplicationArguments args) {
        String strArgs = String.join("|", args.getSourceArgs());
        logger.info("MyApplicationRunner started with arguments:{}", strArgs);

    }
}

按照之前的做法执行相同的命令,可以看到MyApplicationRunner 中run方法也成功执行

在这里插入图片描述

ApplicationArguments是对参数(main方法)做了进一步的处理,可以解析–name=value的,我们就可以通过name来获取value(而CommandLineRunner只是获取–name=value,获取的是一个整体字符串,并不能解析参数,如果想对参数做精细化处理,ApplicationRunner 更为合适),可以接收–foo=bar这样的参数。
–getOptionNames()方法可以得到foo这样的key的集合。
–getOptionValues(String name)方法可以得到bar这样的集合的value。

比如输入的参数命令如下

java -jar Add-WaterMark-0.0.1-SNAPSHOT.jar --doo=bar --developer.name=hulei

ApplicationRunner 就可以根据doo和developer.name这两个key获取后面的值bar 和hulei

下面对MyApplicationRunner改造下:

@Component
public class MyApplicationRunner implements ApplicationRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyApplicationRunner.class);

    @Override
    public void run(ApplicationArguments args) {
        logger.info("===MyApplicationRunner==={}", Arrays.asList(args.getSourceArgs()));
        logger.info("===getOptionNames========{}",args.getOptionNames());
        logger.info("===getOptionValues======={}",args.getOptionValues("doo"));
        logger.info("==getOptionValues========{}",args.getOptionValues("developer.name"));

    }
}

可以看到成功按照键值对的形式解析了我们启动时输入的参数
在这里插入图片描述
而CommandLineRunner做不到精细解析,只能打印一个字符串参数
在这里插入图片描述

五、Order控制执行顺序

在 spring boot 程序中,我们可以使用不止一个实现 CommandLineRunner 和 ApplicationRunner 的 bean。为了有序执行这些 bean 的 run() 方法,可以使用 @Order 注解或 Ordered 接口。例子中我们创建了两个实现 CommandLineRunner 接口的 bean 和两个实现 ApplicationRunner 接口的 bean。可以使用 @Order 注解按顺序执行这四个 bean。

  1. CommandLineRunnerBean1.java
@Component
@Order(1)
public class CommandLineRunnerBean1 implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("CommandLineRunnerBean 1");
    }
}

  1. ApplicationRunnerBean1.java
@Component
@Order(2)
public class ApplicationRunnerBean1 implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments arg0) throws Exception {
        System.out.println("ApplicationRunnerBean 1");
    }
}

  1. CommandLineRunnerBean2.java
@Component
@Order(3)
public class CommandLineRunnerBean2 implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("CommandLineRunnerBean 2");
    }
}

  1. ApplicationRunnerBean2.java
@Component
@Order(4)
public class ApplicationRunnerBean2 implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments arg0) throws Exception {
        System.out.println("ApplicationRunnerBean 2");
    }
}

这几个类上都有注解@Order,并且按照1,2,3,4的顺序规定了启动顺序,启动结果如下:

在这里插入图片描述

六、总结

本篇文章详细介绍了ApplicationRunnerCommandLineRunner两个接口的用法和区别,掌握这两个强大的接口可以为我们的日常开发带来很大便利,比如笔者开发中有个获取字典值的操作,从redis中获取,需要转为java对象Map,才能使用。而从redis中获取转为java对象这个过程长达十秒(可能redis是分布式的,对象本身也比较大,再加上带宽限制这个主要原因)我无法忍受,所以笔者在启动服务的时候就从分布式缓存redis中获取到这个大对象,转成java对象,后续就能在应用中直接使用了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

15秒下雨短视频:成都柏煜文化传媒有限公司

15秒下雨短视频&#xff1a;瞬间的诗意与情感共鸣 在数字时代的浪潮中&#xff0c;短视频以其独特的魅力&#xff0c;成为了人们生活中不可或缺的一部分。其中&#xff0c;一段仅15秒的下雨短视频&#xff0c;成都柏煜文化传媒有限公司 或许在时间长河中只是一瞬间&#xff0c…

用通俗易懂方式讲解:快速部署大模型 ChatGLM3 并进行推理

在深入了解了一些大模型的知识之后&#xff0c;最好的方法是亲自动手搭建一个开源的大模型&#xff0c;以更深入地理解其工作原理。 在此基础上&#xff0c;我们将以 ChatGLM3 为例进行部署及推理&#xff0c;从而进一步探索大模型的应用和实践。 ChatGLM3简介&#xff1a; …

2024年度总结:不可错过的隧道IP网站评估推荐

随着网络技术的飞速发展&#xff0c;隧道IP服务成为了许多企业和个人在进行网络活动时的得力助手。作为专业的测评团队&#xff0c;我们经过一整年的深入研究和测试&#xff0c;为大家带来了三款备受瞩目的隧道IP网站推荐——品易HTTP、极光HTTP和一G代理。接下来&#xff0c;我…

智慧校园-教材管理系统总体概述

智慧校园教材管理系统&#xff0c;作为教育信息化进程的又一实践成果&#xff0c;正逐步改变着传统教材管理的模式。该系统通过集成先进的信息技术&#xff0c;对教材从采购、分配、使用到回收的全过程进行了全面的数字化改造&#xff0c;旨在构建一个高效、透明、节约的教材管…

Python生成和识别二维码教程

引言 二维码&#xff08;QR Code&#xff09;在日常生活中非常常见&#xff0c;广泛应用于支付、登录验证、信息分享等场景。本文将介绍如何使用Python生成和识别二维码&#xff0c;适合初学者快速上手。我们将使用qrcode和pyzbar库来实现这一功能。 环境准备 在开始之前&am…

IT项目管理中如何沟通?

IT项目管理中的沟通是保证项目顺利进行的关键。以下是一些创意文案&#xff0c;用以强调和展示在IT项目管理中进行有效沟通的策略和重要性&#xff1a; 代码与文化的编织者&#xff1a;在IT项目管理中&#xff0c;沟通不仅需要技术的精准&#xff0c;更需要文化的融合&#xff…

Qt中用QLabel创建状态灯

首先ui设计中分别创建了4个大灯和4个小灯。 编辑.h文件 #ifndef LED_H #define LED_H#include <QWidget> #include <QLabel>QT_BEGIN_NAMESPACE namespace Ui { class Led; } QT_END_NAMESPACEclass Led : public QWidget {Q_OBJECTpublic:Led(QWidget *parent n…

苹果电脑文件清理软件哪个好 苹果电脑如何清理内存和垃圾文件 cleanMyMac X 4.8.0激活号码

苹果电脑一直以其出色的性能和优雅的设计吸引着无数忠实用户。然而&#xff0c;众所周知&#xff0c;随着时间的推移和使用的增加&#xff0c;您的Mac可能会开始变慢&#xff0c;就像任何高性能设备&#xff0c;长时间使用后总会积累些“灰尘”。但在苹果电脑上就不是真的灰尘哦…

Vite:打包时去除console

需求描述 在生产环境下&#xff0c;Vite打包项目时&#xff0c;需要去除开发时加入的console、debugger调试信息&#xff0c;但是又不想引入terser。 解决方案 esbuild 参考&#xff1a; esbuild - API 修改配置 修改vite.config.js配置文件&#xff0c;新增配置项如下&…

6. 较全的Open3D点云数据处理(python)

注意&#xff1a;以下内容来自博客爆肝5万字❤️Open3D 点云数据处理基础&#xff08;Python版&#xff09;_python 点云 焊缝-CSDN博客&#xff0c;这篇博客写的全且详细&#xff0c;在这里是为了记笔记方便查看&#xff0c;并非抄袭。 1.点云的读写 代码如下&#xff1a; …

SQL33 找出每个学校GPA最低的同学 解法详解

题目截图&#xff1a; 建表代码&#xff1a; drop table if exists user_profile; CREATE TABLE user_profile ( id int NOT NULL, device_id int NOT NULL, gender varchar(14) NOT NULL, age int , university varchar(32) NOT NULL, gpa float, active_days_within_30 int…

一次进程虚拟内存占用超过200G问题分析

在对智驾软件系统资源进行分析时&#xff0c;发现一个进程虚存占用过高&#xff0c;超过200G top查看内存占用 有一个node应用占用了200G的虚拟内存 pmap查看该进程内存情况 pmap -x -p 8496结果显示有两个异常点&#xff0c;刚好和虚存使用总量吻合 一个50G和一个170G的堆…

什么是BIOS,如何进入BIOS设置?

什么是BIOS&#xff0c;如何进入BIOS设置&#xff1f;标题 &#x1f5a5;️ 什么是BIOS&#xff0c;如何进入BIOS设置&#xff1f;——默语的深入解析摘要引言正文内容&#x1f9e9; 什么是BIOS&#xff1f;&#x1f527; 如何进入BIOS设置&#xff1f;⚙️ 常见的BIOS设置选项…

将json对象转为xml进行操作属性

将json对象转为xml进行操作属性 文章目录 将json对象转为xml进行操作属性前端发送json数据格式写入数据库格式-content字段存储&#xff08;varchar(2000)&#xff09;Question实体类-接口映射对象QuestionContent 接收参数对象DAO持久层Mapper层Service层Controller控制层接收…

6月26日-时间记录和统计

首先&#xff0c;我们根据你提供的时间记录&#xff0c;将活动进行分类并计算每个类别的持续时间&#xff0c;然后计算它们各自所占的百分比。以下是具体的分类和计算步骤&#xff1a; 1. **思想活动**&#xff1a; - 持续时间&#xff1a;15分48秒 2. **学习活动**&#xff1a…

Java代码基础算法练习-计算看完一本书的天数-2024.06.29

任务描述&#xff1a; 一本书有 n 页&#xff0c;小明第一天看 1 页&#xff0c;以后每天都比前一天多看 2 页&#xff0c;计算小明看完整本书 需要多少天&#xff1f; 解决思路&#xff1a; 每天都比前一天多看 2 页&#xff0c;输入的页数 n 为判断标准&#xff0c;while 循…

堆排序思想分享

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

SAP ATP可用性检查简介

Availability Check,就是可用性检查,指的是要检查一下此物料是否能满足我的需求。 接到一张销售订单(SALES ORDER),客户要求数量为100PC,并且客户要求的出货日期是2024-07-01,此时我们的销售人员肯定会想到底能否出货给客人呢?系统中建立此单时,SAP就会做一个所谓的检…

一键掌控,文件格式转换无忧!轻松驾驭各种文件格式,高效管理您的数字世界

信息爆炸的时代&#xff0c;我们每天都会接触到各种各样的文件格式。无论是工作文档、图片、视频还是音频文件&#xff0c;它们都以不同的格式存在于我们的电脑和移动设备中。然而&#xff0c;不同的软件和应用往往只支持特定的文件格式&#xff0c;这给我们的工作和生活带来了…

Petal-X :心血管疾病临床风险可视化工具

心血管疾病&#xff08;Cardiovascular diseases, CVDs&#xff09;是全球致死的首要原因&#xff0c;但在大多数情况下&#xff0c;它们是可以通过行为干预来预防的。因此&#xff0c;在个体层面上&#xff0c;有效地传达心血管疾病的风险以及通过风险因素的修改来预计风险降低…