Springboot 初始化操作

在使用Springboot过程中,或多或少我们会遇到在Springboot启动时要初始化类,或者加载文件之类的一些操作。关于初始化,主要分为两类,一类是在程序启动后的执行初始化操作,另一类是Bean实例化时执行初始化操作,本文将介绍这两类初始化操作常用的一些类和注解,相信总会有一种方法适合你的。

程序启动后的初始化

ApplicationRunner 接口

ApplicationRunner接口主要作用是在应用程序启动完成后执行一些自定义的逻辑。通过实现ApplicationRunner接口并重写其run方法,我们可以定义在应用程序启动后需要执行的任务逻辑。当Spring Boot应用程序启动完成后,ApplicationRunner接口的run方法会被自动调用,执行你在该方法中定义的任务。

ApplicationRunner接口特别适用于那些需要在应用程序启动后立即执行的任务,例如数据初始化、缓存预热等。此外,它也常被用作定时任务的触发点,在应用程序启动时即启动一些定时任务。

run方法中,我们可以通过传入的ApplicationArguments对象获取到启动应用程序时传递的命令行参数,这为我们提供了更多的灵活性和控制力。

以下是一个简单的示例,演示了如何使用 ApplicationRunner 接口:

/*** @author 公众号(索码理)*/
@Component
public class MyApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("ApplicationRunner 执行初始化操作...");// 获取命令行参数的值String name = args.getOptionValues("name").get(0); // 获取名为"name"的参数的值boolean hasCode = args.containsOption("code"); // 检查是否存在名为"code"的标志System.out.println("name: " + name);System.out.println("hasCode: " + hasCode);System.out.println("=============分割线=============");}
}

idea中设置启动参数:

控制台输出结果:

在这个示例中,我们使用getOptionValues()方法来获取命令行参数的值,该方法返回一个字符串列表。如果参数是标志而不是键值对,则可以使用containsOption()方法检查参数是否存在。从控制台中我们可以看到 ApplicationRunner 接口的初始化操作是在Tomcat启动之后即程序启动之后进行初始化的。

CommandLineRunner 接口

CommandLineRunner 接口是 Spring Boot 中的一个功能性接口,用于在 Spring Boot 应用程序启动后执行特定的任务或代码。我们可以使用它在 Spring Boot 应用程序启动后执行一些初始化操作,例如加载初始数据、执行特定的业务逻辑、启动后台任务等。

这个接口只定义了一个方法 run(String... args),该方法在 Spring Boot 应用程序启动后会被自动调用,其中 args 参数是命令行参数。开发者需要实现这个接口,并在实现类中编写需要在应用程序启动后执行的代码逻辑。

Spring Boot 在启动时会自动检测所有实现了 CommandLineRunner 接口的 bean,并在应用程序启动后按照它们在 Spring 上下文中的注册顺序依次调用其 run 方法。

使用 CommandLineRunner 接口可以方便地进行应用程序启动后的初始化工作,而不需要显式地编写启动时的逻辑,从而使应用程序的启动过程更加灵活和可扩展。

以下是一个简单的示例,演示了如何使用 CommandLineRunner 接口:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;/*** @author 公众号(索码理)*/
@Component
public class MyCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner 执行初始化操作...");System.out.println("CommandLineRunner args = " + Arrays.toString(args));}
}

在这个示例中,我们创建了一个名为 MyCommandLineRunner 的类,它实现了 CommandLineRunner 接口,并重写了 run 方法,在方法中打印参数表示应用程序启动成功。从控制台中我们可以看到 CommandLineRunner 接口的初始化操作是在Tomcat启动之后即程序启动之后进行初始化的。

ApplicationRunner 和CommandLineRunner 的区别

了解完ApplicationRunnerCommandLineRunner 接口之后,不难发现,它们都是在程序启动后执行特定操作的,那它们之间有什么不同呢?

ApplicationRunnerCommandLineRunner 接口都继承了Runner接口, 它们之间的区别主要在于方法签名传递参数的方式:

  1. 方法签名

    • CommandLineRunner 接口中的 run 方法签名为 void run(String... args),其中参数 args 是一个字符串数组,用于接收命令行参数。
    • ApplicationRunner 接口中的 run 方法签名为 void run(ApplicationArguments args),其中参数 argsApplicationArguments 类型的对象,用于接收应用程序的启动参数。
  2. 参数传递方式

    • CommandLineRunner 中,启动参数是作为字符串数组直接传递给 run 方法的参数。
    • ApplicationRunner 中,启动参数是作为 ApplicationArguments 对象传递给 run 方法的参数,这个对象提供了更丰富的参数处理功能,例如获取非标准的命令行参数、获取命令行参数的选项和值等。

在大多数情况下,这两个接口可以互换使用,选择哪一个主要取决于对命令行参数处理的需求。如果你只需要简单地接收命令行参数,那么使用 CommandLineRunner 就足够了。但如果你需要更复杂的参数处理,例如获取命令行参数的选项和值,那么使用 ApplicationRunner 会更方便。

另外,需要注意的是,Spring Boot 在启动时会优先调用实现了 ApplicationRunner 接口的 bean 的 run 方法,如果没有找到 ApplicationRunner 类型的 bean,则会去调用实现了 CommandLineRunner 接口的 bean 的 run 方法。

Bean的实例化

InitializingBean 接口

InitializingBean 接口是Spring框架的一个接口,它允许Bean在其属性被设置后进行自定义初始化操作。这个接口定义了一个方法afterPropertiesSet(),在Bean的所有属性被设置后立即调用。
这使得 InitializingBean 可以作为自定义初始化回调的标记接口,用于执行那些需要在对象依赖注入完成之后进行的初始化操作。

通过实现InitializingBean接口,可以确保在Spring容器完成Bean的实例化和属性设置后执行特定的初始化逻辑。这在需要在Bean初始化阶段执行一些特定操作时非常有用,例如数据验证、资源初始化或与其他Bean的交互等。

以下是一个简单的示例,演示了如何实现InitializingBean接口:

/*** @author sunlong* @author 公众号(索码理)*/
public class MyInitializingBean implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean 执行初始化操作...");}
}

注入MyInitializingBean 实例:

@Configuration
public class ServiceConfig {@Beanpublic MyInitializingBean MyInitializingBean() {System.out.println("MyInitializingBean 注入。。。");return new MyInitializingBean();}
}

控制台打印结果:

MyInitializingBean 注入。。。
InitializingBean 执行初始化操作...

在这个例子中,当Spring容器实例化MyInitializingBean 时,会自动调用afterPropertiesSet()方法来执行初始化逻辑。

@PostConstruct注解

@PostConstruct注解是Java EE 5规范中引入的一个注解,主要在JSR 250标准中定义。它被设计用于在对象实例化后、依赖注入完成之时自动调用某个方法,以执行初始化操作。这个注解通常用于Java EE和Spring等框架中,标记那些需要在依赖注入后执行的方法。

其主要用途包括在依赖注入完成后,执行一些需要依赖注入对象的初始化逻辑。例如,你可以在@PostConstruct注解的方法中进行一些属性的赋值、资源的初始化、连接的建立等操作。

在Spring框架中,当Spring创建了一个类的实例并完成依赖注入后,如果该类中存在被@PostConstruct注解的方法,Spring会自动调用这个方法。需要注意的是,@PostConstruct注解只能用于非静态方法,并且只会被容器调用一次。如果一个类中存在多个被@PostConstruct注解的方法,它们的执行顺序并不确定,但你可以通过@Order注解来指定执行顺序。

在Spring项目中,一个bean的初始化过程中,方法执行的先后顺序为:Constructor > @Autowired > @PostConstruct。即首先执行构造方法,然后进行依赖注入,最后执行初始化操作。

关于@PostConstruct注解的方法,它可以有返回值,尽管通常我们将其返回类型设置为void。而且,这个方法的访问修饰符可以是publicprotectedprivate,因为它的功能是通过反射来实现的。此外,这个方法不能是static的,但可以是final的。

InitializingBean接口相比,@PostConstruct注解提供了更清晰、更灵活的方式来定义初始化方法,而且不需要实现任何特定的接口。

以下是一个简单的示例,演示了如何实现**@PostConstruct**注解:

@Component
public class PostConstructComponent {@PostConstructpublic void init() {// 执行初始化操作System.out.println("PostConstruct执行初始化操作...");}
}

在这个示例中,当Spring容器实例化PostConstructComponent 并完成依赖注入后,会调用init()方法来执行初始化逻辑。

@Bean

@Bean注解主要用于将对象(通常是bean)存入Spring的IoC)容器中。与@Controller@Service@Repository@Component等类注解不同,@Bean注解是方法级别的,它通过将当前方法的返回值对象放入容器中来实现对象的管理。通过这种方式我们可以自定义bean的创建逻辑。

在Spring配置类中,你可以使用@Bean注解来定义一个或多个bean。默认情况下,bean的名称与带有@Bean注解的方法名相同,但你也可以使用name属性来指定一个自定义的名称。

@Bean注解有一个initMethod属性,用于指定bean的初始化方法。

例如:

创建MyService 类:

public class MyService {public void initMethod() {System.out.println("MyService 执行初始化操作...");}
}

注入MyService

@Configuration
public class ServiceConfig {@Bean(initMethod = "initMethod")public MyService myService() {System.out.println("MyService 注入。。。");return new MyService();}
}

在这个例子中,MyService的实例会被创建,并且作为名为myService的bean注册到Spring容器中,在MyService被实例化时,会自动调用MyServiceinitMethod方法。

InitializingBean 接口、@PostConstruct注解、@Bean注解区别

InitializingBean接口、@PostConstruct注解和@Bean注解在Spring框架中都有各自的作用,尽管它们都可以用于执行Bean的初始化逻辑,但它们还是有所区别的:

  • InitializingBean@PostConstruct主要用于执行Bean的初始化逻辑,但它们来源于不同的框架或规范。InitializingBean是Spring特有的,而@PostConstruct是Java EE规范的一部分,由Java EE容器调用。
  • @Bean主要用于声明和定义Bean,虽然可以在其方法内部执行初始化逻辑,但其主要目的是定义和注册Bean。
  • InitializingBean@PostConstruct都可以在Bean的属性被注入之后执行初始化逻辑,但@PostConstruct的方法在InitializingBeanafterPropertiesSet()方法之前执行。

在Spring中,通常推荐使用@PostConstruct注解来执行初始化逻辑,因为它更符合Java EE规范,并且与Spring的依赖注入机制结合得更好。

总结

本文介绍了程序启动后和Bean实例化后可以进行的初始化操作,有生就有死,能够初始化就能够销毁,下篇文章将介绍如何在程序关闭时和Bean销毁时进行一系列操作,感兴趣可以关注一下,敬请期待。

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

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

相关文章

3D Tiles 规范(一概述)

3D Tiles 专为流式传输和渲染大量 3D 地理空间内容而设计,例如摄影测量、3D 建筑、BIM/CAD、实例化要素和点云。它定义了分层数据结构和一组提供可渲染内容的Tile格式。3D Tiles 没有定义内容可视化的明确规则;客户可以根据自己认为合适的方式可视化 3D …

如何理解Vue 3组件的component关键字

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Verilog仿真跨模块调用内部信号的方法

在Verilog仿真时如果需要调用某子模块中的信号在本模块中使用可以使用层次化引用的方法,而不需要在rtl部分用端口引出来。 引用方式:当前例化模块名.子例化模块名.子子例化模块名.参数 将需要的信号引出。 注意是用例化模块名而不是用子模块名&#xff…

【C++】二维数组传参方式

最近刚开始刷剑指offer,刚做到第三题的时候,发现C二维数组的传参方式和C语言略有些不同,所以在这篇博客中,会列出C/C常见的二维数组传参方式。(本方式和代码都是基于vs环境所编写) 一.C语言二维数组传参方式…

CCF区块链论文录用资讯--ICSE 2024

ICSE是CCF A类会议 (软件工程/系统软件/程序设计语言) 其2024录用了13篇区块链论文 Smart Contract and DeFi Security Tools: Do They Meet the Needs of Practitioners? 智能合约和 DeFi 安全工具:它们满足从业者的需求吗? St…

SegAnyGAussians(SAGA)项目配置和运行

GitHub项目地址:Jumpat/SegAnyGAussians: The official implementation of SAGA (Segment Any 3D GAussians) (github.com) 一、项目准备 1、下载原项目的zip包解压 2、下载third_party目录下的两个模块,放到对应目录下 3、下载预训练模型和数据集 数据…

非计算机专业,如何从事研发岗位的建议!

首先,非计算机专业的毕业生通过读研和专门的培训是完全可以进入IT行业的,目前IT行业内也有大量非计算机专业毕业的技术开发(研发)人员,其中有不少人也非常优秀,发展空间同样比较大。 虽然IT行业内整体的人才…

IPFS分布式存储系统

一、 引言 IPFS是InterPlanetary File System的缩写。它是一个分布式的网络传输协议,它可以把文件分成很多小块放到服务器的不同地方,然后用一种特别的方式来寻找和传输这些小块。这样,我们就可以更快、更安全、更抗容错了的存储文件了。 可能…

从小到大输出四个整数(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int a, b, c, d;int t 0;//提示用户&#xff1b;printf("请输入四个整数a b c d&…

python怎么判断整数

isinstance()函数 可以用来判断变量的类型&#xff0c;它返回的是一个布尔值&#xff0c;False or True。 >>>isinstance("123",str) >>>Flase >>>isinstance(123,int) >>>True >>>isinstance({123},list) >>&g…

【大数据】分布式文件系统HDFS

目录 1.什么是分布式文件系统 2.HDFS的特点 3.HDFS的核心概念 4.HDFS的体系结构 5.HDFS的配置建议 6.HDFS的局限性 7.HDFS的存储机制 7.1.数据冗余机制 7.2.错误与恢复 8.HDFS数据读写过程 1.什么是分布式文件系统 分布式文件系统是整个大数据技术的基础&#xff0c…

京东AI数字人“采销东哥”首秀观看量破2000万;天工 SkyMusic 音乐大模型开放公测

&#x1f989; AI新闻 &#x1f680; 京东AI数字人“采销东哥”首秀观看量破2000万 摘要&#xff1a;京东AI数字人“采销东哥”由京东云言犀打造&#xff0c;在其直播首秀中亮相并迅速吸引超2000万观看量。尽管“采销东哥”的外形和口音与创始人刘强东相似&#xff0c;但其直…

C语言的OJ判题机设计与实现

1. 接收判题入参 判题需要作答代码、测试输入和期望输出、编译器名称、时空限制。对于支持special judge的还需要传入是否为sj和sj代码。推荐使用消息队列&#xff0c;应对高并发的比赛情况会比较好。 但是消息队列是异步的&#xff0c;我为了快点实现能提交后在当前页面获得判…

量子密钥分发系统的设计与实现(二):光路子系统初步讨论

通过上一篇文章&#xff0c;我们对量子密钥分发系统的基本架构、硬件结构以及密钥分发流程进行了初步的总体介绍&#xff0c;从本文开始&#xff0c;我们就基于系统顶层的架构设计&#xff0c;开始从模块到器件&#xff0c;从硬件到软件开始详细讨论QKD系统的设计与实现。本文主…

双向链表详解

目录 带头双向循环链表带头双向循环链表的实现带头双向循环链表的功能实现创造新节点LTNode* CreateLTNode(LTDataType x)代码 初始化链表LTNode*LTInit(LTNode* phead)代码 打印链表void LTPrint(LTNode* phead)代码 链表尾插void LTPushBack(LTNode* phead, LTDataType x)代码…

C#语法知识之运算符

3、运算符 1、算数运算符 1、赋值符号 //把右侧的值赋给左侧的变量2、算数运算符 _ * / float f 1 / 2f; %3、算数运算符的优先级 //乘除余优先级高于加减 括号可以改变优先级&#xff0c;优先计算括号内的内容4、算数运算符的复合运算 复合运算符是用于自己 自己进行运算…

源码解读——SplitFed: When Federated Learning Meets Split Learning

源码地址 1. 源码概述 源码里一共包含了5个py文件 单机模型&#xff08;Normal_ResNet_HAM10000.py&#xff09;联邦模型&#xff08;FL_ResNet_HAM10000.py&#xff09;本地模拟的SFLV1&#xff08;SFLV1_ResNet_HAM10000.py&#xff09;网络socket下的SFLV2&#xff08;SF…

51单片机入门_江协科技_33~34_OB记录的自学笔记_LED呼吸灯与PWM直流马达调速

33. 直流电机驱动(PWM) 33.1. 直流电机介绍 •直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极&#xff0c;当电极正接时&#xff0c;电机正转&#xff0c;当电极反接时&#xff0c;电机反转 •直流电机主要由永磁体&#xff08;定子&#xff09;、线圈&…

MySQL 死锁案例解析一则

原文链接&#xff1a;https://www.modb.pro/db/448666 一、问题背景某业务模块反馈数据库最近出现过几次死锁告警的情况&#xff0c;本文总结了这次死锁排查的全过程&#xff0c;并分析了导致死锁的原因及解决方案。希望给大家提供一个死锁的排查及解决思路。基础环境&#xff…

一.NODE MCU(ESP8285,ESP8286)开发环境搭建

一.序言: 1.esp8285长什么样? 2.esp8285是什么,能做什么? 通过上面图片,看到上面的芯片,是带有多个阵脚的单片机。实际上,看着该芯片很小,但是却具有完整的wifi无线蓝牙功能,它本身可以运行一个极简的linux小系统,并且该极简的小linux系统具备无线蓝牙功能。。它同…