Spring实现Bean的初始化和销毁的方式

2025-05-08 02:50

本文主要是介绍Spring实现Bean的初始化和销毁的方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Spring实现Bean的初始化和销毁的方式》:本文主要介绍Spring实现Bean的初始化和销毁的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教...

在前面的章节当中介绍完毕了ApplicationContext,也就是应用上下文。我们说BeanFactory是面向开发者的,ApplicationContext才是面向使用者的,实际上也是如此。在ApplicationContest当中我们对BeanFactory进行了进一步的集成,实现了自动化的XML文件读取,注册BeanFacoryPostProcess,注册BeanPostProcess,以及提前初始化单列Bean。

以上都是属于Bean生命周期的一部分,是通过Spring自动管理的,除此之外Spring还允许用户自定义初始化与销毁方法,同样也可以通过Spring自动化调用。

一、Bean的初始化

在实现初始化与销毁之前我们需要先考虑一下什么时候进行初始化,什么时候要销毁。

很简单,初始化发生在创建Bean的时候,而销毁发生在容器或者虚拟机关闭的时候。那么对于初始化来说他是针对对应的Bean的,也就是说在创建的时候执行,而销毁是一个统一的行为,当容器关闭时候需要对指定Bean进行统一的销毁。

那么明白了上述逻辑后我们就开始我们的逻辑实现

首先容器的初始化行为是正对Bean本身,实际上和BeanPostProcessor非常类似,只不过初始化的行为更具象罢了。

首先我们需要在BeanDefinition当中添加初始化的方法名,该名称用于用户通过XML/注解方式自定义初始化的方法

private String initMethodName;

第二步,定义用于初始化的父类,这样我们的Bean就可以集成该类,重写初始化方法。

public interface InitializingBean {  
    void afterPropertiesSet();  
}

现在再回到AbstractAutowireCapableBeanFactory当中的初始化方法initializeBean当中,在这里执行完了BeanPostProcess的前置增强之后,执行用户定义的初始化方法。

private void initializeBean(String beanName, Object bean,BeanDefinition beanDefinition) {  
    // 执行初始化之前的BeanPostProcessor前置处理  
    Object wrappedBean  = applyBeanPostProcessorsBeforeInitialization(bean, beanName);  
  
    // 执行初始化方法  
    try {  
        invokeInitMethods(beanName , wrappedBean , beanDefinition);  
    } catch (Exception e) {  
        throw new BeansException("调用 bean 的 init 方法[" + beanName + "] 失败", e);  
    }  
  
    // 执行初始化之前的BeanPostProcessor后置  
    wrappedBean = applyBeanPostProcessorsAfterInitialization(bean , beanName);  
}

初始化的逻辑也很简单,首先判断用户是否实现了InitializingBean这个接口,如果实现了则调用其重写的afterPropertiesSet初始化方法。之后再判断用户是否是自己指定了自定义的初始化方法,如果指定则通过反射获取到该方法并执行即可。

private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception{  
    if (bean instanceof InitializingBean){  
        ((InitializingBean) bean).afterPropertiesSet();  
    }  
  
    // 处理用户自定义的初始化方法  
    if (StrUtil.isNotEmpty(beanDefinition.getInitMethodNphpame())){  
        Method initMethod = ClassUtil.getPublicMethod(bean.getClass(), beanDefinition.getInitMethodName());  
        if (initMethod == null) {  
            throw new BeansException(String.format("在Bean:%s 当中找不到名为:%s 的初始化方法",beanName,beanDefinition.getInitMethodName()));  
        }  
        initMethod.invoke(bean);  
    }  
}

二、Bean的销毁

Bean的销毁相对于初始化来说最大的区别在于,初始化时正对单个Bean,销毁是针对所有要销毁的Bean。

也就是说,我们需要定一个Map集合存储所有要销毁的Bean,在容器关闭时遍历集合,执行其销毁方法。

首先我们需要在BeanDefinition当中添加销毁的方法名,该名称用于用户通过XML/注解方式自定义销毁的方法

private String destroyMethodName;

第二步,定义用于销毁的父类,这样我们的Bean就可以集成该类,重写销毁方法。

public interface DisposableBean {  
  
    public void destroy();  
}

然后我们需要回到ConfigurableApplicationContext,因为实际上Bean的销毁时应用上下文的行为,在我们关闭ApplicationContext的时候才会执行。

public interface ConfigurableApplicationContext extends ApplicationContext {  
    /**  
     * 刷新容器,重新加载并初始化所有配置和Bean  
     */    
    void refresh();  
  
    /**  
     * 关闭ApplicationContext  
     */    
    void close();  
  
  
    void registerShutdownHook();  
}

在AbstractApplicationContext实现这些方法,先看下面的代码,这里可能会有一个疑问就是getBeanFactory().destroySingletons(); 通过完整的代码我们可以知道getBeanFactory()返回的是一个DefaultListableBeanFactory的对象,那么我们也要在其父类当中实现该方法。

/**  
 * 关闭ApplicationContext  
 */@Override  
public void close() {  
    doClose();  
}  
  
private void doClose() {  
    destroyBeans();  
  
}  
  
private void destroyBeans() {  
    getBeanFactory().destroySingletojavascriptns();  
}  
  
@Override  
public void registerShutdownHook() {  
    Thread shutdownHook = new Thread(this::doClose);  
    Runtime.getRuntime().addShutdownHook(shutdownHook);  
}

首先我们要明确一点,在Sjavascriptpring当中所有接口都被指责化了,也就是说不同接口有着不同的功能,而Bean的销毁也属于单列Bean的生命周期当中,所以我们要在DefaultSingletonBeanRegistry当中实现该方法,除此之外destroySingletons该方法我们还需要在ConfigurableBeanFactory当中定义。

其中ConfigurableBeanFactory与DefaultSingletonBeanRegistry之间都继承于SingletonBeanRegistry,但是我们不在SingletonBeanRegistry当中定义destroySingletons接口,二者时通过组合继承实现的

public void destroySingletons(){  
    Set<String> beanNames = disposableBeans.keySet();  
    for (String beanName : beanNames) {  
        DisposableBean disposableBean = disposableBeans.remove(beanName);  
        // 执行销毁方法  
        disposableBean.destroy();  
    }  
  
}
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {  
  
    /**  
     * 添加一个 BeanPostProcessor 到工厂中。  
     * BeanPostProcessor 可以在 Bean 初始化前后执行自定义逻辑。  
     *  
     * @param beanPostProcessor 要添加的 BeanPostProcessor 实例  
     */  
    void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);  
  
  
    /**  
     * 销毁单例bean  
     */    
    void destroySingletons();  
}

其实到这里所有的逻辑就结束了,下面写一个测试

package org.qlspringframework.beans.ioc.bean;  
  
import org.qlspringframework.beans.factory.DisposableBean;  
import org.qlspringframework.beans.factory.InitializingBean;  
  
/**  
 * @author jixu  
 * @title People  
 * @date 2025/4/7 09:54  
 */public class People implements DisposableBean, InitializingBean {  
  
    private String name;  
    private Integer age;  
  
    private Car car;  
  
    public Car getCar() {  
        return car;  
    }  
  
    public void setCar(Car car) {  
        this.car = car;javascript  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Integer getAge() {  
        return age;  
    }  
  
    public void setAge(Integer age) {  
        this.age = age;  
    }  
  
    @Override  
    public String toString() {  
   www.chinasem.cn     return "People{" +  
                "name='" + name + '\'' +  
                ", age=" + age +  
                ", car=" + car +  
                '}';  
    }  
  
    @Override  
    public void destroy() {  
        System.out.println("People destroy");  
    }  
  
    @Override  
    public void afterPropertiesSet() {  
        System.out.println("People init");  
    }  
}
public class InitAndDestroyMethodTest {  
  
    @Test  
    public void testInitAndDestroy(){  
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");  
        classPathXmlApplicationContext.registerShutdownHook();  
    }  
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持China编程(www.chinasem.cn)。

这篇关于Spring实现Bean的初始化和销毁的方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154514

相关文章

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter