当前位置: 首页 > news >正文

Spring Boot启动时执行初始化操作的几种方式

场景

项目中,经常需要在启动过程中初始化一些数据,如从数据库读取一些配置初始化,或从数据库读取一些热点数据到redis进行初始化缓存。

方式一:实现CommandLineRunner 接口重写run方法逻辑

CommandLineRunner是Spring提供的接口,定义了一个run()方法,用于执行初始化操作。

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class InitConfigCommand implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner:"+"{}"+"接口实现方式重写");}
}

CommandLineRunner的执行时机为Spring beans初始化之后,因此CommandLineRunner的执行一定是晚于@PostConstruct的。
若有多组初始化操作,则每一组操作都要定义一个CommandLineRunner派生类并实现run()方法。这些操作的执行顺序使用@Order(n)来设置,n为int型数据。

@Component
@Order(99)
public class CommandLineRunnerA implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("初始化:CommandLineRunnerA");}
}@Component
@Order(1)
public class CommandLineRunnerB implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("初始化:CommandLineRunnerB");}
}

如上,会先执行CommandLineRunnerB的run(),再执行CommandLineRunnerA的run()。
@Order(n)中的n较小的会先执行,较大的后执行。n只要是int值即可,无需顺序递增。

方式二:实现ApplicationRunner接口重写run方法逻辑

ApplicationRunner接口与CommandLineRunner接口类似,都需要实现run()方法。二者的区别在于run()方法的参数不同:

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
public class InitConfig implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("项目启动初始化");}
}

ApplicationRunner接口的run()参数为ApplicationArguments对象,因此可以获取更多项目相关的内容。
ApplicationRunner接口与CommandLineRunner接口的调用时机也是相同的,都是Spring beans初始化之后。因此ApplicationRunner接口也使用@Order(n)来设置执行顺序。

方式三:使用@PostConstruct注解的方式

对于注入到Spring容器中的类,在其成员函数前添加@PostConstruct注解,则在执行Spring beans初始化时,就会执行该函数。

但由于该函数执行时,其他Spring beans可能并未初始化完成,因此在该函数中执行的初始化操作应当不依赖于其他Spring beans。

@Component
public class Construct {@PostConstructpublic void doConstruct() throws Exception {System.out.println("初始化:PostConstruct");}
}

初始化顺序

  1. @PostConstruct 注解方法
  2. CommandLineRunner接口实现
  3. ApplicationRunner接口实现

扩展

@PostConstruct注解使用在方法上,它可以被用来标注一个非静态的 void 方法,这个方法会在该类被 Spring 容器初始化后立即执行。因为它的执行时机是在依赖注入之后,对象构造完成之后,也就是说是在@Autowired注入之后执行。所以这里可以进行一些初始化操作,如某些需要在对象创建后才能进行的数据初始化操作。

需要注意以下几点:

  1. @PostConstruct 只能用在方法上面,而不能用在属性或构造函数上。
  2. 一个类中可以有多个使用 @PostConstruct 注解的方法,但执行顺序并不是固定的。
  3. @PostConstruct 注解的方法在本类中必须是无参数的,如果有参数,那么这个方法不会被执行。
  4. @PostConstruct 注解的方法在实现上可以使用任意修饰符。

假设我们有一个需要初始化数据的类:

public class InitService {private List<String> data;public InitService() {this.data = Arrays.asList("A", "B", "C");}@PostConstructpublic void init() {data.add("D");}public List<String> getData() {return this.data;}
}

当我们实例化 InitService 时,构造函数会为 data 属性赋初值,而 @PostConstruct 注解的 init 方法会在 Spring 容器实例化完 InitService 后被执行,将 “D” 添加到 data 列表中。所以当我们调用 getData() 方法时,返回的列表应该是 [A, B, C, D]。

接下来看看 @Autowired 和@PostConstruct 的具体执行顺序

@Service
public class TestA {static {System.out.println("staticA");}@Autowiredprivate TestB testB;public TestA() {System.out.println("这是TestA 的构造方法");}@PostConstructprivate void init() {System.out.println("这是TestA的 init 方法");testB.test();}
}
@Service
public class TestB {static {System.out.println("staticB");}@PostConstructprivate void init() {System.out.println("这是TestB的init 方法");}public TestB() {System.out.println("这是TestB的构造方法");}void test() {System.out.println("这是TestB的test方法");}
}

构造方法:在对象初始化时执行。执行顺序在static静态代码块之后。

服务启动后,输出结果如下:

staticA
这是TestA 的构造方法
staticB
这是TestB的构造方法
这是TestB的init 方法
这是TestA的 init 方法
这是TestB的test方法

结论为:等@Autowired注入后,在执行@PostConstruct注解的方法。

方式四:静态代码块

static静态代码块,在类加载的时候即自动执行。

使用的static静态代码块,实现原理为@Component + static代码块, spring boot项目在启动过程中,会扫描@Component 并初始化相应的类,类的初始化过程会运行静态代码块。

@Component
public class WordInitConfig {static {WordSegmenter.segWithStopWords("初始化分词");}
}

所以得到结论

static>constructer>@Autowired>@PostConstruct>ApplicationRunner>CommandLineRunner

相关文章:

Spring Boot启动时执行初始化操作的几种方式

场景 项目中&#xff0c;经常需要在启动过程中初始化一些数据&#xff0c;如从数据库读取一些配置初始化&#xff0c;或从数据库读取一些热点数据到redis进行初始化缓存。 方式一:实现CommandLineRunner 接口重写run方法逻辑 CommandLineRunner是Spring提供的接口&#xff0…...

考研失败, 学点Java打小工——Day3

1 编码规范——卫语句 表达异常分支时&#xff0c;少用if-else方式。   比如成绩判断中对于非法输入的处理&#xff1a; /*>90 <100 优秀>80 <90 良好>70 <80 一般>60 <70 及格<60 不及格*/Testpu…...

【Stable Diffusion】入门-01:原理简介+应用安装(Windows)+生成步骤

【Stable Diffusion】入门&#xff1a;原理简介应用安装&#xff08;Windows&#xff09;生成步骤 原理简介应用安装 原理简介 稳定扩散生成模型(Stable Diffusion)是一种潜在的文本到图像扩散模型&#xff0c;能够在给定任何文本输入的情况下生成照片般逼真的图像。 应用安…...

VueX详解

Vuex 主要应用于Vue.js中管理数据状态的一个库通过创建一个集中的数据存储&#xff0c;供程序中所有组件访问 使用场景 涉及到非父子关系的组件&#xff0c;例如兄弟关系、祖孙关系&#xff0c;甚至更远的关系组件之间的联系中大型单页应用&#xff0c;考虑如何更好地在组件外部…...

2023 年 9 月青少年软编等考 C 语言一级真题解析

目录 T1. 日期输出思路分析 T2. 计算 (a b) (c - b) 的值思路分析 T3. 有一门课不及格的学生思路分析 T4. 特殊求和T5. 比 n 小的最大质数 T1. 日期输出 给定两个整数&#xff0c;表示一个日期的月和日。请按照 "MM-DD" 的格式输出日期&#xff0c;即如果月和日不…...

避免阻塞主线程 —— Web Worker 示例项目

前期回顾 迄今为止易用 —— 的 “盲水印“ 实现方案-CSDN博客https://blog.csdn.net/m0_57904695/article/details/136720192?spm1001.2014.3001.5501 目录 CSDN 彩色之外 &#x1f4dd; 前言 &#x1f6a9; 技术栈 &#x1f6e0;️ 功能 &#x1f916; 如何运行 ♻️ …...

matlab 基操~

MATLAB基本操作 1. 对象定义 使用sym定义单个对象、使用syms定义多个对象 2. 使用limit求极限 $$ \lim_{v \rightarrow a} f(x) $$ limit(f,v,a) % 使用limit(f,v,a,left)可求左极限 3. 导数 使用diff(f,v,n)对$ f(v)v^{t-1} $求 $ n $ 阶导 $ \frac{d^nf}{d^nv} $&#xf…...

HTML5、CSS3面试题(一)

1、H5 的新特性有哪些&#xff1f;C3 的新特性有哪些&#xff1f;&#xff08;必会&#xff09; H5 新特性 1、拖拽释放(Drap and drop) API ondrop 拖放是一种常见的特性&#xff0c;即抓取对象以后拖到另一个位置 在 HTML5 中&#xff0c;拖放是标准的一部分&#xff0c;任…...

图片压缩神器源码系统:无损画质 带完整的代码安装包以及搭建教程

在数字化时代&#xff0c;图片已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;随着图片数量的增加和质量的提升&#xff0c;存储空间的问题也日益凸显。如何在保证图片质量的前提下&#xff0c;有效减少图片的大小&#xff0c;成为了一个亟待解决的问题。罗峰…...

探索SOCKS5代理、代理IP、HTTP与网络安全

在这个数字化时代&#xff0c;网络安全已成为我们日常生活中不可或缺的一部分。作为一名软件工程师&#xff0c;深入理解网络通信的核心技术&#xff0c;如SOCKS5代理、代理IP、HTTP协议&#xff0c;以及它们在网络安全中的应用&#xff0c;对于设计和实施安全的网络应用至关重…...

【Python学习篇】Python基础入门学习——你好Python(一)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…...

【通信原理笔记】【二】随机信号分析——2.2 平稳随机过程

文章目录 前言一、平稳随机过程1.1 广义平稳过程1.2 遍历性 二、两个随机过程之间的关系2.1 联合平稳2.2 随机过程的相关关系2.2.1 随机变量的不相关2.2.2 随机过程的不相关 总结 前言 我们学习了随机信号以及随机信号的相关函数与功率谱的计算方法&#xff0c;但是这种计算还…...

新火种AI|GPT-4诞生1年,OpenAI把它放到了机器人上

作者&#xff1a;一号 编辑&#xff1a;美美 ChatGPT拥有了身体&#xff0c;机器人也有了灵魂。 从OpenAI在去年3月14日拿出GPT-4后&#xff0c;已经过了整整一年。显然&#xff0c;在GPT-4诞生之后的这一年&#xff0c;一切都迭代得太快了&#xff0c;从GPT-4展现多模态能力&…...

8-图像放大

其实&#xff0c;就是开辟一个zoomwidth&#xff0c;zoomheight的内存&#xff0c;再分别赋值即可。 void CDib::Maginify(float xZoom, float yZoom) { //指向原图像指针 LPBYTE p_data GetData(); //指向原像素的指针 LPBYTE lpSrc; //指向缩放图像对应像素的指针 LPBYTE l…...

java实现压缩文件夹(层级压缩)下载,java打包压缩文件夹下载

工具类如下 打包下载方法&#xff1a;exportZip&#xff08;支持整个文件夹或单文件一起&#xff09; 注意:前端发送请求不能用ajax&#xff0c;form表单提交可以&#xff0c;location.href也可以&#xff0c;window.open也可以&#xff0c;总之就ajax请求就是不行 import com.…...

Visual Studio 2022 配置“Debug|x64”的 Designtime 生成失败。IntelliSense 可能不可用。

今天写代码&#xff0c;无缘无故就给我整个这个错误出来&#xff0c;我一头雾水。 经过我几个小时的奋战&#xff0c;终于解决问题 原因就是这个Q_INTERFACES(&#xff09;宏&#xff0c;我本想使用Q_DECLARE_INTERFACE Q_INTERFACES这两个Qt宏实现不继承QObject也能使用qobjec…...

Pandas教程16:DataFrame列标题批量重命名+空df数据判断+列名顺序重排

---------------pandas数据分析集合--------------- Python教程71&#xff1a;学习Pandas中一维数组Series Python教程74&#xff1a;Pandas中DataFrame数据创建方法及缺失值与重复值处理 Pandas数据化分析&#xff0c;DataFrame行列索引数据的选取&#xff0c;增加&#xff0c…...

React.FC介绍

React.FC是React中的一种函数组件类型&#xff0c;是在TypeScript中使用的一个泛型&#xff0c;FC即Function Component的缩写&#xff0c;表示一个接收props作为输入并返回JSX元素的函数组件。 使用React.FC可以为组件定义类型&#xff0c;提供props的类型作为泛型参数&#x…...

为什么要用scrapy爬虫库?而不是纯python进行爬虫?

为什么要用scrapy爬虫库&#xff1f;而不是纯python进行爬虫&#xff1f; Scrapy的优点Scrapy节省的工作使用纯Python编写爬虫的不足 Scrapy是一个使用Python编写的开源和协作的web爬虫框架&#xff0c;它被设计用于爬取网页数据并从中提取结构化数据。Scrapy的强大之处在于其广…...

C:数据结构王道

初始化顺序表&#xff08;顺序表中元素为整型&#xff09;&#xff0c;里边的元素是1,2,3&#xff0c;然后通过scanf读取一个元素&#xff08;假如插入的是6&#xff09;&#xff0c;插入到第2个位置&#xff0c;打印输出顺序表&#xff0c;每个元素占3个空格&#xff0c;格式为…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...