如何实现bean初始化摧毁方法的注入

 更新时间:2023年04月28日 10:46:03   作者:Anoxia1  
这篇文章主要为大家介绍了如何实现bean初始化摧毁方法的注入详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

实现 bean 初始化、摧毁方法的配置与处理

spring支持我们自定义 bean 的初始化方法和摧毁方法。配置方式可以通过 xml 的 init-methoddestory-method配置,或者实现 InitializingBeanDisposableBean接口,来完成自定义的初始化和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) &amp;&amp; !(bean instanceof DisposableBean &amp;&amp; "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 方法");
    }
}

测试结果

以上就是如何实现bean初始化摧毁方法的注入的详细内容,更多关于bean初始化摧毁方法注入的资料请关注脚本之家其它相关文章!

相关文章

  • Java中常用的设计模式之建造者模式详解

    Java中常用的设计模式之建造者模式详解

    这篇文章主要为大家详细介绍了Java中常用的设计模式之建造者模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • spring boot里增加表单验证hibernate-validator并在freemarker模板里显示错误信息(推荐)

    spring boot里增加表单验证hibernate-validator并在freemarker模板里显示错误信息(推

    这篇文章主要介绍了spring boot里增加表单验证hibernate-validator并在freemarker模板里显示错误信息的相关资料,需要的朋友可以参考下
    2018-01-01
  • Java多线程中断机制三种方法及示例

    Java多线程中断机制三种方法及示例

    这篇文章主要介绍了Java多线程中断机制三种方法及示例,向大家分享了这三种方法的介绍几代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • 深入学习MyBatis中的参数(推荐)

    深入学习MyBatis中的参数(推荐)

    大家日常使用MyBatis经常会遇到一些异常,想要避免参数引起的错误,我们需要深入了解参数。想了解参数,我们首先看MyBatis处理参数和使用参数的全部过程。下面这篇文章主要给大家介绍了MyBatis中参数的的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-06-06
  • java右下角弹窗示例分享

    java右下角弹窗示例分享

    这篇文章主要介绍了java右下角弹窗示例,需要的朋友可以参考下
    2014-04-04
  • Java中的引用类型和使用场景详细

    Java中的引用类型和使用场景详细

    这篇文章介绍的是Java中的引用类型和使用场景,主要内容展开Java中的引用类型,有强引用、软引用 、弱引用、虚引用,需要的朋友可以参考一下
    2021-10-10
  • SpringMVC接收页面表单参数

    SpringMVC接收页面表单参数

    本篇文章主要介绍了SpringMVC接收页面表单参数的相关知识,具有很好的参考价值。下面跟着小编一起来看下吧
    2017-05-05
  • Java中的static关键字用法总结

    Java中的static关键字用法总结

    这篇文章主要介绍了Java中的static关键字用法总结,static是Java50个关键字之一,static关键字可以用来修饰代码块表示静态代码块,修饰成员变量表示全局静态成员变量,修饰方法表示静态方法,需要的朋友可以参考下
    2023-11-11
  • springboot实现邮箱验证码功能

    springboot实现邮箱验证码功能

    这篇文章主要为大家详细介绍了springboot实现邮箱验证码功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • Java中Object toString方法简介_动力节点Java学院整理

    Java中Object toString方法简介_动力节点Java学院整理

    Object类在Java里面是一个比较特殊的类,JAVA为了组织这个类组织得比较方便,它提供了一个最根上的类,相当于所有的类都是从这个类继承,这个类就叫Object。接下来通过本文给大家介绍Object toString方法,需要的的朋友参考下吧
    2017-05-05

最新评论