六种方式,教你在SpringBoot初始化时搞点事情!

前言

在实际工作中总是需要在项目启动时做一些初始化的操作,比如初始化线程池、提前加载好加密证书.......

那么经典问题来了,这也是面试官经常会问到的一个问题:有哪些手段在Spring Boot 项目启动的时候做一些事情?

方法有很多种,下面介绍几种常见的方法。

1、监听容器刷新完成扩展点ApplicationListener<ContextRefreshedEvent>

ApplicationContext事件机制是观察者设计模式实现的,通过ApplicationEvent和ApplicationListener这两个接口实现ApplicationContext的事件机制。

Spring中一些内置的事件如下:

  1. ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。

  2. ContextStartedEvent:当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。

  3. ContextStoppedEvent:当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。

  4. ContextClosedEvent:当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。

  5. RequestHandledEvent:这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。

好了,了解上面这些内置事件后,我们可以监听ContextRefreshedEvent在Spring Boot 启动时完成一些操作,代码如下:

@Component
public class TestApplicationListener implements ApplicationListener<ContextRefreshedEvent>{@Overridepublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {System.out.println(contextRefreshedEvent);System.out.println("TestApplicationListener............................");}
}

高级玩法

可以自定事件完成一些特定的需求,比如:邮件发送成功之后,做一些业务处理。

  1. 自定义EmailEvent,代码如下:

public class EmailEvent extends ApplicationEvent{private String address;private String text;public EmailEvent(Object source, String address, String text){super(source);this.address = address;this.text = text;}public EmailEvent(Object source) {super(source);}//......address和text的setter、getter
}
  1. 自定义监听器,代码如下:

public class EmailNotifier implements ApplicationListener{public void onApplicationEvent(ApplicationEvent event) {if (event instanceof EmailEvent) {EmailEvent emailEvent = (EmailEvent)event;System.out.println("邮件地址:" + emailEvent.getAddress());System.our.println("邮件内容:" + emailEvent.getText());} else {System.our.println("容器本身事件:" + event);}}
}
  1. 发送邮件后,触发事件,代码如下:

public class SpringTest {public static void main(String args[]){ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");//创建一个ApplicationEvent对象EmailEvent event = new EmailEvent("hello","abc@163.com","This is a test");//主动触发该事件context.publishEvent(event);}
}

2、SpringBootCommandLineRunner接口

当容器初始化完成之后会调用CommandLineRunner中的run()方法,同样能够达到容器启动之后完成一些事情。这种方式和ApplicationListener相比更加灵活,如下:

  • 不同的CommandLineRunner实现可以通过@Order()指定执行顺序

  • 可以接收从控制台输入的参数。

下面自定义一个实现类,代码如下:

@Component
@Slf4j
public class CustomCommandLineRunner implements CommandLineRunner {/*** @param args 接收控制台传入的参数*/@Overridepublic void run(String... args) throws Exception {log.debug("从控制台接收参数>>>>"+ Arrays.asList(args));}
}

运行这个jar,命令如下:

java -jar demo.jar aaa bbb ccc

以上命令中传入了三个参数,分别是aaabbbccc,这三个参数将会被run()方法接收到。如下图:

图片

源码分析

读过我的文章的铁粉都应该知道CommandLineRunner是如何执行的,原文:头秃系列,二十三张图带你从源码分析Spring Boot 启动流程~

Spring Boot 加载上下文的入口在org.springframework.context.ConfigurableApplicationContext()这个方法中,如下图:

图片

调用CommandLineRunner在callRunners(context, applicationArguments);这个方法中执行,源码如下图:

图片

3、SpringBootApplicationRunner接口

ApplicationRunnerCommandLineRunner都是Spring Boot 提供的,相对于CommandLineRunner来说对于控制台传入的参数封装更好一些,可以通过键值对来获取指定的参数,比如--version=2.1.0

此时运行这个jar命令如下:

java -jar demo.jar --version=2.1.0 aaa bbb ccc

以上命令传入了四个参数,一个键值对version=2.1.0,另外三个是分别是aaabbbccc

同样可以通过@Order()指定优先级,如下代码:

@Component
@Slf4j
public class CustomApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {log.debug("控制台接收的参数:{},{},{}",args.getOptionNames(),args.getNonOptionArgs(),args.getSourceArgs());}
}

通过以上命令运行,结果如下图:

图片

源码分析

CommandLineRunner一样,同样在callRunners()这个方法中执行,源码如下图:

图片

4、@PostConstruct注解

前三种针对的是容器的初始化完成之后做的一些事情,@PostConstruct这个注解是针对Bean的初始化完成之后做一些事情,比如注册一些监听器...

@PostConstruct注解一般放在Bean的方法上,一旦Bean初始化完成之后,将会调用这个方法,代码如下:

@Component
@Slf4j
public class SimpleExampleBean {@PostConstructpublic void init(){log.debug("Bean初始化完成,调用...........");}
}

5、@Bean注解中指定初始化方法

这种方式和@PostConstruct比较类似,同样是指定一个方法在Bean初始化完成之后调用。

新建一个Bean,代码如下:

@Slf4j
public class SimpleExampleBean {public void init(){log.debug("Bean初始化完成,调用...........");}
}

在配置类中通过@Bean实例化这个Bean,不过@Bean中的initMethod这个属性需要指定初始化之后需要执行的方法,如下:

@Bean(initMethod = "init")public SimpleExampleBean simpleExampleBean(){return new SimpleExampleBean();}

6、 InitializingBean接口

InitializingBean的用法基本上与@PostConstruct一致,只不过相应的Bean需要实现afterPropertiesSet方法,代码如下:

@Slf4j
@Component
public class SimpleExampleBean implements InitializingBean {@Overridepublic void afterPropertiesSet()  {log.debug("Bean初始化完成,调用...........");}
}

总结

实现方案有很多,作者只是总结了常用的六种,学会的点个赞。

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

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

相关文章

2.1基本算法之枚举7827:质数的和与积

两个质数的和是S&#xff0c;它们的积最大是多少&#xff1f; #include<bits/stdc.h>//万能头 using namespace std;//不用说 int fun(int n){//创建一个自定义的函数&#xff0c;方便之后判断质数 int asqrt(n);//平方根&#xff0c;让电脑轻松一点 for(int i2…

0 OpenHarmony开源鸿蒙NEXT星河版内核嵌入式编程

开源鸿蒙NEXT星河版内核嵌入式编程 作者将狼才鲸创建日期2024-03-08 CSDN文章阅读地址Gitee文章下载地址 一、前景提要 2024年1月18日&#xff0c;华为放出HarmonyOS NEXT 鸿蒙星河版开发者预览版本&#xff08;不是HarmonyOS NEXT版&#xff0c;是HarmonyOS NEXT星河版&…

Remote host closed connection during handshake

问题原因&#xff1a; HTTPS通过TSLv1和TSLv1.2协议通信 JDK7默认是TSLv1&#xff0c;JDK8默认是TSLv1.2 假如服务端是TSLv1.2&#xff0c;客户端是TSLv1&#xff0c;访问就会出现 Remote host closed connection during handshake 异常 解决方法 方法一&#xff…

字符串库函数

字符串库函数 使用字符串函数需要#include<cstring>字符串函数都根据\0来判断字符串结尾形参为char[]类型&#xff0c;则实参可以是char数组或字符串常量 字符串拷贝 strcpy(char [ ] dest,char [ ] src);//拷贝src到dest 字符串比较大小 int strcmp(char [ ] s1,ch…

如何系统的学习python编程

学习Python编程需要有一个系统的方法。这里有一些简单的步骤&#xff1a; 从基础开始&#xff1a;首先&#xff0c;要明白计算机编程的基本概念&#xff0c;比如变量、条件语句、循环等。然后学习Python的基础语法&#xff0c;就像学习任何一门新语言一样。 选择好资源&#x…

火爆新品推荐!AI大模型应用和ai 数字人开发!

火爆新品来袭&#xff01;AI大模型应用和AI数字人开发成为当下科技界的热点话题。随着人工智能技术的不断发展&#xff0c;AI大模型应用已经开始在各个领域大放异彩。从医疗诊断到金融风控&#xff0c;从自然语言处理到智能推荐&#xff0c;AI大模型的应用场景愈发广泛&#xf…

java如何学习

要高效学习Java&#xff0c;可遵循以下步骤&#xff1a; 1. 掌握基础知识&#xff1a;熟悉Java语法、数据类型、运算符、控制流程等。 2. 学习面向对象&#xff1a;理解封装、继承、多态等概念&#xff0c;掌握类、对象、接口的使用。 3. 深入学习Java核心类库&#xff1a;学习…

PyCharm 显示无法加载文件 D:\...,因为在此系统上禁止运行脚本。

PyCharm 显示无法加载文件 D:…&#xff0c;因为在此系统上禁止运行脚本。 PyCharm 显示 无法加载文件 D:\python test\AI_CV\venv\Scripts\activate.ps1&#xff0c;因为在此系统上禁止运行脚本。 解决方法&#xff1a; winx点击Windows PowerShell&#xff08;管理员&#…

基于yolov5的SAR舰船检测系统,可进行图像目标检测,也可进行视屏和摄像检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示&#xff1a; 基于yolov5的SAR舰船检测系统&#xff0c;系统既能够实现图像检测&#xff0c;也可以进行视屏和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的SAR舰船检测系统是在pytorch框架下实现的&#xff0c;这是一个完整的项目&…

爬虫实战——巴黎圣母院新闻【内附超详细教程,你上你也行】

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

【python爬虫】免费爬取网易云音乐完整教程(附带源码)

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 所属专栏:爬虫实战,零基础、进阶教学 景天的主页:景天科技苑 文章目录 网易云逆向网易云逆向 https://music.163.com/ 下载云音乐 胡广生等,可以选择自己喜欢的歌曲 首先,我们可以先根据…

动态线程池的简单实现思路

什么是动态线程池&#xff1f; 在线程池日常实践中我们常常会遇到以下问题&#xff1a; 代码中创建了一个线程池却不知道核心参数设置多少比较合适。 参数设置好后&#xff0c;上线发现需要调整&#xff0c;改代码重启服务非常麻烦。 线程池相对于开发人员来说是个黑箱&#x…

使用Pytorch导出自定义ONNX算子

在实际部署模型时有时可能会遇到想用的算子无法导出onnx&#xff0c;但实际部署的框架是支持该算子的。此时可以通过自定义onnx算子的方式导出onnx模型&#xff08;注&#xff1a;自定义onnx算子导出onnx模型后是无法使用onnxruntime推理的&#xff09;。下面给出个具体应用中的…

100个网络基础知识普及

目录 1、什么是链接&#xff1f; 2、OSI 参考模型的层次是什么&#xff1f; 3、什么是骨干网&#xff1f; 4、什么是 LAN&#xff1f; 5、什么是节点&#xff1f; 6、什么是路由器&#xff1f; 7、什么是点对点链接&#xff1f; 8、什么是匿名 FTP&#xff1f; 9、什么…

机器学习中的线性代数

基础知识的的复习: 线性代数——深度学习花书第二章 - 知乎 矩阵分解 特征值分解。 PCA(Principal Component Analysis)分解,作用:降维、压缩。 SVD(Singular Value Decomposition)分解,也叫奇异值分解。 矩阵分解的主要应用是:降维、聚类分析、数据预处理、低维度特征学…

Keepalive 解决nginx 的高可用问题

一 说明 keepalived利用 VRRP Script 技术&#xff0c;可以调用外部的辅助脚本进行资源监控&#xff0c;并根据监控的结果实现优先动态调整&#xff0c;从而实现其它应用的高可用性功能 参考配置文件&#xff1a; /usr/share/doc/keepalived/keepalived.conf.vrrp.localche…

学校课程:固体物理学--黄昆·CH1

1. 序言 固体的结构概念 固体材料分晶体和非晶体 理想晶体原子排列具有周期性&#xff0c;长程有序 非晶体不具有以上性质 准晶体是新发现的 晶体中原子分子规则排列&#xff0c;导致晶体具有规则的几何外形 1. 1-1 晶格/晶体格子&#xff1a; 晶体中原子排列的具体方式…

三八妇女节智慧花店/自动售花机远程视频智能监控解决方案

一、项目背景 国家统计局发布的2023年中国经济年报显示&#xff0c;全年社会消费品零售总额471495亿元&#xff0c;比上年增长7.2%。我国无人零售整体发展迅速&#xff0c;2014年市场规模约为17亿元。无人零售自助终端设备市场规模超过500亿元&#xff0c;年均复合增长率超50%。…

正则表达式在QT开发中的应用

一.正则表达式在QT开发中的使用&#xff1a; 1.模式匹配与验证&#xff1a;正则表达式最基本的作用就是进行模式匹配&#xff0c;它可以用来查找、识别或验证一个字符串是否符合某个特定的模式。例如&#xff0c;在表单验证中&#xff0c;可以使用正则表达式来检查用户输入的邮…

Agent——记忆模块

在基于大模型的 Agent架构设计方面,论文[1]提出了一个统一的框架,包括Profile模块、Memory模块、Planning模块和Action模块。其中长期记忆的状态维护至关重要,在 OpenAI AI 应用研究主管 Lilian Weng 的博客《基于大模型的 Agent 构成》[2]中,将记忆视为关键的组件之一,下…