SpringBoot 核心功能 - ApplicationRunner && CommandLineRunner 的使用
前言
如果想在SpringApplication启动后做一些操作,那么除了可以监听ApplicationReadyEvent事件外,还可以实现ApplicationRunner或CommandLineRunner接口.
ApplicationRunner
新建一个ApplicationRunner实现,代码如下:
package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* 自定义{@link ApplicationRunner}实现
*
* @author Bruse
*/
@Slf4j
@Component
public class CustomApplicationRunner implements ApplicationRunner {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(ApplicationArguments args) throws Exception {
// 简单打印一下应用参数
log.info("arguments is {}", Arrays.toString(args.getSourceArgs()));
}
}
这里ApplicationRunner的run()方法实现,仅仅打印一下应用参数,所以在启动Java Application前,先在配置一些应用参数【笔者这里用到的IDEA版本为2023.1.4】:
启动SpringApplication,输出如下:
可以看到CustomApplicationRunner的run()方法在SpringApplicaiton启动后被回调,并且输出我们配置的应用参数.
CommandLineRunner
新建一个CommandLineRunner实现,代码如下:
package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 自定义{@link CommandLineRunner}实现
*/
@Slf4j
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(String... args) throws Exception {
// 这里简单做一下参数打印
log.info("args is {}", Arrays.toString(args));
}
}
启动SpringApplication,控制台成功输出:
两者的区别
ApplicationRunner和CommandLineRunner两个接口唯一的区别在于,两者run()方法的参数不一样,虽然参数都是Java应用启动时设置的参数,但ApplicationRunner将参数包装成了ApplicationArguments,CommandLineRunner则没有多过包装,直接就是传递一个String[]给实现者进行参数读取.
优先级设置
如果必须按特定顺序调用ApplicationRunner或CommandLineRunner的run()方法的话,可以使用Order注解或实现Ordered接口.
对CustomApplicationRunner稍作调整,让其实现Ordered接口,改动后代码如下:
package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 自定义{@link ApplicationRunner}实现
*
* @author Bruse
*/
@Slf4j
@Component
public class CustomApplicationRunner implements ApplicationRunner, Ordered {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("arguments is {}", Arrays.toString(args.getSourceArgs()));
}
@Override
public int getOrder() {
// 返回优先级,数值越小,优先级越高
return 0;
}
}
对CustomCommandLineRunner稍作调整,给其加上@Order注解,代码如下:
package geek.springboot.application.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 自定义{@link CommandLineRunner}实现
*/
@Slf4j
@Order(-1) // 数值越小,优先级越高
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
/**
* 在SpringApplication启动完成后,该方法会被回调,可以在这里做一些操作
*
* @param args 启动Java Application时设置的程序参数
* @throws Exception 异常
*/
@Override
public void run(String... args) throws Exception {
log.info("args is {}", Arrays.toString(args));
}
}
CustomCommandLineRunner定义的优先级比CustomApplicationRunner高,也就是CustomCommandLineRunner的run()永远优于CustomApplicationRunner的run(),控制台输出如下:
注意不要做耗时的任务
本质上启动SpringApplication的线程,和回调ApplicationRunner、CommandLineRunner的run()方法的线程是同一个,所以注意不要在run()中执行过于复杂耗时的任务.
源码分析
查看SpringApplication的run()方法,关键代码如下:
查看callRunners()方法,可以看到逻辑非常简单,就是获取所有ApplicationRunner和CommandLineRunner的实现,然后做一个优先级排序,最后回调run()方法.
而且从源码中还可以看出,ApplicationRunner和CommandLineRunner的run()回调,是在ApplicationReadyEvent事件广播之前,核心代码如下:
结尾
本文章源自《Learn SpringBoot》专栏,感兴趣的话还请关注点赞收藏.
上一篇文章:《SpringBoot核心特性——应用事件监听》
推荐阅读
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
SpringBoot 核心功能 - ApplicationRunner && CommandLineRunner 的使用
-
SpringBoot2.x 基础知识:使用 CommandLineRunner 或 ApplicationRunner
-
使用 SpringBoot 和 Vue 开发支付宝扫码支付功能的实践指南
-
三分钟带你了解手机内部硬件-主要影响手机性能的有以下几点 CPU - *处理器(手机中的大脑) CPU 是计算思考以及处理事物的。 比如:我们日常玩手机,什么最重要?毫无疑问是手机打开软件很流畅,使用各种功能不卡。 这就是CPU的性能,那什么影响 CPU 的因素有哪些? 架构 架构是 CPU 的基础,对于处理器的整体性能起到了决定性的作用,不同架构的处理器同主频下,性能差距可以达到2-5倍。可见架构的重要性。 那么什么是架构呢? 打个比方,架构就是一栋楼的框架。至于最终楼什么样子,就由处理器的厂商决定了,但是有一点,如果说这栋楼房的结构设计出来容纳多少人,那么最后建好的房子也要在这个范围内。同理,如果使用相同架构的处理器,那么本质上不会有太大的区别。 看一下主流手机的架构 处理器对比.jpg 从上图可见:高通 和 苹果都是自主设计,所以说它们牛还是有一定的道理的。不同的架构, 性能和功耗也是不同的。架构决定了 主频、核心数、带宽等和运算量直接相关的东西。目前很多手机打广告都是说 多少核的机器。但是并不是说核越多性能就越强,你没看见,苹果双核就能吊打高通和联发科吗? 制程 制程 专指:事物运作程序的处理过程。常指手机芯片框架的运算速度量。 简单的说就是电路板中电路与电路之间的距离,目前已经发展到纳米级别。 制程越小,可以向芯片中塞入更多的晶体管,随之而来的好处还有:降低电量和成本、散热。 制程数的确定 这里有人要问,为什么制程的数字是这些,而不是别的数字,比如有28nm,为什么没有29nm? 这其实是有一定规律的。根据早期国际半导体蓝图规划,由五个在相关领域较为发达的国家共同制定,约定下一代制程要在上一代基础上做到晶体管数量不变,芯片面积缩小一半。由这一关系可以算出前一代制程要比后一代大√2倍,所以能算出后一代大概数值。纵观整个处理器制程变化,除了少部分特殊的外,都遵循着这一规则。 近代制程的发展 2014 年底,三星宣布了世界首个 14nm FinFET 3D 晶体管进入量产,标志着半导体晶体管进入 3D 时代。发展到今天,三星拥有了四代 14nm 工艺,第一代是苹果 A9 上面的 FinFET LPE(Low Power Early),第二代则是用在猎户座 骁龙 820 和骁龙 625 上面的 FinFET LPP(Low Power Plus)。第三代是 FinFET LPC,第四代则是目前的 FinFET LPU。至于 10nm 工艺,三星则更新到了第三代(LPE/LPP/LPC)。 目前为止,三星已经将 70000 多颗第一代 LPE(低功耗早期)硅晶片交付给客户。三星自家的猎户座 8895,以及高通的骁龙 835,都采用这种工艺制造,而 10nm 第二代 LPP 版和第三代 LPU 版将分别在年底和明年进入批量生产。 手机芯片市场上已经进入了 10nm、7nm 处理器的白热化竞争阶段,而 14/16nm 制程的争夺也不过是一两年前的事。 总线位宽 总线位宽决定输入/输出设备之间一次数据传输的信息量,用位(bit)表示,如总线宽度为8位、16位、32位和64位。
-
SaaS新十年:餐饮数字化转型的三大趋势- 一体化系统 2012年,亚马逊公司前首席科学家安德里亚斯·维真德表示,数据是新石油,但石油需要加以提炼后才能使用,从事数据处理的公司就是炼油厂。 如今,数据是一种资源已经获得广泛共识,这场竞争的核心就在于数据的占有和应用能力,占有的数据越多、运用数据能力越强的公司就越有价值。 对于to B型企业,只做单点业务很难产生差异化优势,因为数据只有流动起来才有价值,就算CRM功能再好,不能跟收银之类的体系打通也没有意义。 在企业管理层面,由于过往理念、*、各业务的机制不统一,过程标准的规范缺失,导致各系统之间兼容性和集成性难以提高。比如餐饮商家在POS数据、会员管理、供应链管理等不同环节都要面对众多系统供应商,多系统难以融合,由此导致的数据割裂问题日益凸显。 即便前期已实现不同服务商系统间的一体化打通与数据规范统一,但随着餐饮企业发展,不断产生新的功能需求,一家服务商出现软件升级,意味着其他服务商也必须做出对策,这时如果其中任何一家出现应对能力不足或者倒闭情况发生,都会影响餐饮企业的进步发展。 因此,餐饮数字化服务具有天然的all in one属性,没有商家愿意收银用一家的系统,供应链用另一家,资金归集再用另外一家,商户对效率的追求天然决定其必然会选择一家功能最全的系统。 沉淀的数据只是资源,只有用起来,数据的价值才能释放。
-
使用SpringBoot实现视频的在线播放功能