如何实现bean初始化摧毁方法的注入
作者:Anoxia1 发布时间:2023-07-22 05:14:31
标签:bean,初始化,摧毁,方法注入
实现 bean 初始化、摧毁方法的配置与处理
spring支持我们自定义 bean 的初始化方法和摧毁方法。配置方式可以通过 xml 的 init-method
和 destory-method
配置,或者实现 InitializingBean
、DisposableBean
接口,来完成自定义的初始化和bean的销毁。 在项目开发过程中,相信最多看到的是 @PostConstruct
注解标识的方法来进行bean的初始化。
@PostConstruct 是 Spring Framework 提供的注解,可以用于在 Bean 实例化之后执行初始化操作
通过xml配置定义初始化、摧毁方法
BeanDefinition 里面添加 initMethodName、和 destoryMethodName 属性,来记录通过配置注入的初始化和摧毁方法名称。然后在解析 xml 文件的 cn.anoxia.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions
方法中,完成 属性的注入。
protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
....
String initMethod = bean.getAttribute("init-method");
String destroyMethod = bean.getAttribute("destroy-method");
Class<?> clazz = Class.forName(calssName);
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)){
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
// 设置初始化、摧毁方法
beanDefinition.setInitMethodName(initMethod);
beanDefinition.setDestoryMethodName(destroyMethod);
....
}
}
通过实现接口
实现 InitializingBean,DisposableBean 并实现里面的方法,来自定义bean的初始化和摧毁方法
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
void destroy() throws Exception;
}
在 创建bean的过程中,完成方法的注入,区分xml配置与接口实现。
initMethod 方法的注入与执行
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
// 注入属性
applyPropertyValues(beanName, bean, beanDefinition);
// 提供给外部的扩展包装,执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new RuntimeException("bean create error!", e);
}
// 注册实现了 DisposableBean 接口的 Bean 对象
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
registerSingleton(beanName, bean);
return bean;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) throws BeansException {
// 1. 执行 BeanPostProcess before 操作
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
try {
// 执行bean初始化方法
invokeInitMethods(beanName,wrappedBean,beanDefinition);
}catch (Exception e){
throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
}
// 2. 执行 BeanPostProcess after 操作
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean,beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 如果是通过接口实现,直接使用接口提供的方法
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 通过xml配置,获取方法执行
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName)) {
Method method = beanDefinition.getBeanClass().getMethod(initMethodName);
// getMethod 已经做了非空判断
if (null == method) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
method.invoke(bean);
}
}
destroyMethod 方法的注入与执行
提供一个适配器、来完成xml和接口的适配处理。处理逻辑基本与 init方法相似
/**
* bean 摧毁适配器
* @author huangle
* @date 2023/3/7 10:26
*/
public class DisposableBeanAdapter implements DisposableBean {
/**
* bean名字
*/
private final String beanName;
/**
* bean
*/
private final Object bean;
/**
* 销毁方法名称
*/
private String destroyMethodName;
public DisposableBeanAdapter(String beanName, Object bean, BeanDefinition beanDefinition) {
this.beanName = beanName;
this.bean = bean;
this.destroyMethodName = beanDefinition.getDestoryMethodName();
}
@Override
public void destroy() throws Exception {
// 1. 实现 DisposableBean 接口,完成摧毁扩展
if (bean instanceof DisposableBean) {
((DisposableBean) bean).destroy();
}
// 2. 通过xml配置 配置 destroy 方法 实现
if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destory".equals(destroyMethodName))) {
Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
if (null == destroyMethod) {
throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
}
destroyMethod.invoke(bean);
}
}
}
测试
userDao 通过xml配置初始化和摧毁方法,userService 通过继承接口来实现方法。
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="cn.anoxia.springframework.beans.factory.support.UserDao" init-method="initMethod" destroy-method="destroyMethod"/>
<bean id="userService" class="cn.anoxia.springframework.beans.factory.support.UserService">
<property name="name" value="Anoxia"/>
<property name="nickname" value="迪迦"/>
<property name="userDao" ref="userDao"/>
</bean>
<!-- <bean id="myBeanPostProcecssor" class="cn.anoxia.springframework.beans.factory.support.MyBeanPostProcecssor"/>-->
<!-- <bean id="myFactoryPostProcessor" class="cn.anoxia.springframework.beans.factory.support.MyBeanFactoryPostProcessor"/>-->
</beans>
public class UserService implements InitializingBean, DisposableBean{
@Override
public void destroy() throws Exception {
System.out.println("userService执行:destroy 方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("userService执行:init 方法");
}
}
测试结果
来源:https://juejin.cn/post/7224509927914078266


猜你喜欢
- 题目要求思路:模拟解题的核心思想在于逆向思维,不考虑每个子数组中的唯一字符个数,转而考虑每个字符可以作为多少个子数组的唯一字符;所以在计算答
- JAVAWEB dbutils执行sql命令并遍历结果集时不能查到内容的原因及处理方法如下所示:遍历结果集时只遍历bean对象才会只输出第一
- 项目演示演示中只用一个用户登录,只是为了测试功能,实际使用中是根据数据库表内数据来决定的。1 创建工程完成配置1 ieda新建maven项目
- 前言今天刷个题,遇到一个很有趣的问题,关于Comparator的使用,感觉也是一个关于写代码的一些小细节的问题关于ComparatorCom
- 完全属于自己的新闻展示平台,展示给大家,希望大家喜欢。一、新闻的数据库的构建脚本代码如下:(使用的mysql5.0 数据库)SET SQL_
- 背景何为延迟队列?顾名思义,延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费。场景一:在
- 多态性1理解多态性:可以理解为一个事物的多种形态。2何为多态性:对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)3多态的
- 在微信的运营过程中难免会出现一些无法预料的事情,比如在
- 导出的 Jar 包无法运行?导出的 Jar 包找不到 Main class?大概是我对导出 Jar 包的理解不深吧,反正一直不太懂 IDEA
- 本文实例介绍了清除aspx页面缓存的程序实现方法,具体步骤如下:所有用到页面缓存的aspx页面修改以下cs,让它继承一个自定义基类(例如:P
- 最近做了一个项目,其中有一个在线网页交流的需求,好久没写代码了,手都生疏了,于是先写demo练练手,分享到脚本之家平台,以此做个记录,方便自
- 前言最近接了一个项目,甲方不愿意买服务器,但是呢,项目又必须要用文件功能。所以很巧,最近又刚好看到了Minio这个牛逼的工具。正好借此机会记
- 外观模式: 又称门面模式: 外观Facade为子系统的一组接口提供一个一致界面,使得这组子系统易于使用(通过引入一个新的外观角色降低原系统复
- java内存分析类加载的过程类的加载与ClassLoader的理解类的初始化package Collections;public class
- 1、什么是Mybatis?MyBatis是一个优秀的持久层框架,是一个半ORM(对象关系映射)框架,它对jdbc的操作数据库的过程进行封装,
- 1、何为依赖冲突Maven是个很好用的依赖管理工具,但是再好的东西也不是完美的。Maven的依赖机制会导致Jar包的冲突。举个例子,现在你的
- 问题学习完maven后,用maven创建了一个web项目,然后在这个web项目中创建了一个java文件夹并标记这个目录为源码根目录,当我准备
- EntityWrapper的常用方法#WHERE (issue_type = ?) AND (status = ? OR status =
- 本文为大家分享了java摄像头截图的具体代码,供大家参考,具体内容如下本来sun有个jmf组件可以很方便的实现摄像头截图的,不过这版本后来停
- 本文介绍如何通过C# 程序来扫描并读取图片中的文字,这里以创建一个.Net Core程序为例。下面是具体步骤,供参考。程序测试环境:Visu