如何實(shí)現(xiàn)bean初始化摧毀方法的注入
實(shí)現(xiàn) bean 初始化、摧毀方法的配置與處理
spring支持我們自定義 bean 的初始化方法和摧毀方法。配置方式可以通過(guò) xml 的 init-method 和 destory-method配置,或者實(shí)現(xiàn) InitializingBean、DisposableBean接口,來(lái)完成自定義的初始化和bean的銷(xiāo)毀。 在項(xiàng)目開(kāi)發(fā)過(guò)程中,相信最多看到的是 @PostConstruct 注解標(biāo)識(shí)的方法來(lái)進(jìn)行bean的初始化。
@PostConstruct 是 Spring Framework 提供的注解,可以用于在 Bean 實(shí)例化之后執(zhí)行初始化操作
通過(guò)xml配置定義初始化、摧毀方法
BeanDefinition 里面添加 initMethodName、和 destoryMethodName 屬性,來(lái)記錄通過(guò)配置注入的初始化和摧毀方法名稱(chēng)。然后在解析 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);
// 設(shè)置初始化、摧毀方法
beanDefinition.setInitMethodName(initMethod);
beanDefinition.setDestoryMethodName(destroyMethod);
....
}
}通過(guò)實(shí)現(xiàn)接口
實(shí)現(xiàn) InitializingBean,DisposableBean 并實(shí)現(xiàn)里面的方法,來(lái)自定義bean的初始化和摧毀方法
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
void destroy() throws Exception;
}
在 創(chuàng)建bean的過(guò)程中,完成方法的注入,區(qū)分xml配置與接口實(shí)現(xiàn)。
initMethod 方法的注入與執(zhí)行
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
// 注入屬性
applyPropertyValues(beanName, bean, beanDefinition);
// 提供給外部的擴(kuò)展包裝,執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new RuntimeException("bean create error!", e);
}
// 注冊(cè)實(shí)現(xiàn)了 DisposableBean 接口的 Bean 對(duì)象
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
registerSingleton(beanName, bean);
return bean;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) throws BeansException {
// 1. 執(zhí)行 BeanPostProcess before 操作
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
try {
// 執(zhí)行bean初始化方法
invokeInitMethods(beanName,wrappedBean,beanDefinition);
}catch (Exception e){
throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
}
// 2. 執(zhí)行 BeanPostProcess after 操作
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean,beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 如果是通過(guò)接口實(shí)現(xiàn),直接使用接口提供的方法
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 通過(guò)xml配置,獲取方法執(zhí)行
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName)) {
Method method = beanDefinition.getBeanClass().getMethod(initMethodName);
// getMethod 已經(jīng)做了非空判斷
if (null == method) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
method.invoke(bean);
}
}
destroyMethod 方法的注入與執(zhí)行
提供一個(gè)適配器、來(lái)完成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;
/**
* 銷(xiāo)毀方法名稱(chēng)
*/
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. 實(shí)現(xiàn) DisposableBean 接口,完成摧毀擴(kuò)展
if (bean instanceof DisposableBean) {
((DisposableBean) bean).destroy();
}
// 2. 通過(guò)xml配置 配置 destroy 方法 實(shí)現(xiàn)
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);
}
}
}
測(cè)試
userDao 通過(guò)xml配置初始化和摧毀方法,userService 通過(guò)繼承接口來(lái)實(shí)現(xiàn)方法。
<?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執(zhí)行:destroy 方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("userService執(zhí)行:init 方法");
}
}測(cè)試結(jié)果

以上就是如何實(shí)現(xiàn)bean初始化摧毀方法的注入的詳細(xì)內(nèi)容,更多關(guān)于bean初始化摧毀方法注入的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring boot里增加表單驗(yàn)證hibernate-validator并在freemarker模板里顯示錯(cuò)誤信息(推
這篇文章主要介紹了spring boot里增加表單驗(yàn)證hibernate-validator并在freemarker模板里顯示錯(cuò)誤信息的相關(guān)資料,需要的朋友可以參考下2018-01-01
深入學(xué)習(xí)MyBatis中的參數(shù)(推薦)
大家日常使用MyBatis經(jīng)常會(huì)遇到一些異常,想要避免參數(shù)引起的錯(cuò)誤,我們需要深入了解參數(shù)。想了解參數(shù),我們首先看MyBatis處理參數(shù)和使用參數(shù)的全部過(guò)程。下面這篇文章主要給大家介紹了MyBatis中參數(shù)的的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-06-06
Java中的引用類(lèi)型和使用場(chǎng)景詳細(xì)
這篇文章介紹的是Java中的引用類(lèi)型和使用場(chǎng)景,主要內(nèi)容展開(kāi)Java中的引用類(lèi)型,有強(qiáng)引用、軟引用 、弱引用、虛引用,需要的朋友可以參考一下2021-10-10
Java中的static關(guān)鍵字用法總結(jié)
這篇文章主要介紹了Java中的static關(guān)鍵字用法總結(jié),static是Java50個(gè)關(guān)鍵字之一,static關(guān)鍵字可以用來(lái)修飾代碼塊表示靜態(tài)代碼塊,修飾成員變量表示全局靜態(tài)成員變量,修飾方法表示靜態(tài)方法,需要的朋友可以參考下2023-11-11
springboot實(shí)現(xiàn)郵箱驗(yàn)證碼功能
這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)郵箱驗(yàn)證碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
Java中Object toString方法簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Object類(lèi)在Java里面是一個(gè)比較特殊的類(lèi),JAVA為了組織這個(gè)類(lèi)組織得比較方便,它提供了一個(gè)最根上的類(lèi),相當(dāng)于所有的類(lèi)都是從這個(gè)類(lèi)繼承,這個(gè)類(lèi)就叫Object。接下來(lái)通過(guò)本文給大家介紹Object toString方法,需要的的朋友參考下吧2017-05-05

