六种方式,教你在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.hqwc.cn/news/521474.html

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

相关文章

【博士每天一篇文献-实验】Impact of modular organization on dynamical richness_in cortical networks

阅读时间&#xff1a;2023-11-25 1 介绍 年份&#xff1a;2018 作者&#xff1a;Yamamoto H, Moriya S, Ide K, WPI-高级材料研究所 (WPI-AIMR)&#xff0c;东北大学&#xff0c;日本 期刊&#xff1a; Science advances, 引用量&#xff1a;90 这篇论文研究了大脑的模块化组…

Windows11安装FFmpeg最新版本

打开终端: 输入 winget install ffmpeg 然后输入 Y 回车后出现如下图: 正在下载FFmpeg 6.1 安装成功 测试

CSS系列之 颜色代码大全、颜色对照表

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

高效办公-浏览器基本操作

日常我们使用电脑&#xff0c;其实很大部分是用于网络功能&#xff0c;这里面除了客户端程序剩余的就是通过我们的浏览器获取信息或者使用业务系统了&#xff0c;这里就简单学习下浏览器基本常识与操作。 一、浏览器是什么&#xff1f; 白话讲浏览器就是一个软件&#xff0c;我…

Windows Server 2012 R2 安装SNMP服务失败,提示:无法打开匿名级安全令牌。错误:0x8007050543

Windows Server 2012 R2 安装SNMP服务失败&#xff0c;提示&#xff1a;无法打开匿名级安全令牌。错误&#xff1a;0x8007050543 解决方法如下&#xff1a; 1、打开运行&#xff0c;输入&#xff1a;dcomcnfg.exe 2、依次进入&#xff1a;【组件服务】-【计算机】-【我的电脑】…

MyBatis Oracle 批量插入数据

MyBatis Oracle 批量插入数据 1.需求描述2.实现方案2.1 循环 insert 插入2.2 insert all 插入2.3 insert union all 插入 3.分析总结 系统&#xff1a;Win10 JDK&#xff1a;1.8.0_351 IDEA&#xff1a;2022.3.3 1.需求描述 在一次项目中实施过程中&#xff0c;后台需要将地区…

HelpLook 和 confluence:创建知识库我选HelpLook

企业要想快速创建知识库&#xff0c;最好的方法就是利用好工具。而市面上创建知识库的平台多而繁杂&#xff0c;无法在最快时间内判断哪一个是最适合企业解决问题的。HelpLook和confluence功能相似&#xff0c;多数人无法判断并做出最佳选择&#xff0c;今天就跟着LookLook同学…

【动态规划.2】5292. 跳台阶

承接上一篇 升级版&#xff0c;别怕&#xff0c;上一篇弄会了&#xff0c;这个就是 豆芽菜✌️ https://www.acwing.com/problem/content/description/5295/ f1.递归 #include <bits/stdc.h> // 2024-03-08 Come on ! using namespace std; #define ll long l…

HEUFT电源维修x-ray发生器维修HBE211226

HEUFT电源维修x-ray发生器维修HBE211253;海富HEUFT在线液位检测X射线发生器维修&#xff0c;不限型型号系列。 德国海富推出HEUFT在线液位检测装置,满瓶检测系统HEUFT有着强大的功能,它的模块机构能整合很多程序,并依据不同的产品及其包装特性,照相技术,高频技术或X-ray技术。…

linux centos系统搭建samba文件服务器 NetBIOS解析 (超详细)

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; Linux专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; 前言———— Samba 是一个开源软件套件&#xff0c;可为 SMB/CIFS 客户端&#xff08;包括 Windows&#xff09;提供文件…

unicloud 云数据库概念及创建一个云数据库表并添加记录(数据)

云数据库概念 uniCloud提供了一个 JSON 格式的文档型数据库。顾名思义&#xff0c;数据库中的每条记录都是一个 JSON 格式的文档。 它是 nosql 非关系型数据库&#xff0c;如果您之前熟悉 sql 关系型数据库&#xff0c;那么两者概念对应关系如下表&#xff1a; 关系型JSON 文…

Flask python开发篇: 写一个简单的接口

第一步&#xff1a;新建flask项目 参考使用pycharm新建一个项目 打开pycharm&#xff0c;根据下面图中箭头顺序&#xff0c;新建一个flask的项目&#xff1b; 第二步&#xff1a;运行项目&#xff0c; 安装成功以后&#xff0c;会有个app.py文件&#xff0c;打开以后&#…