最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring實現(xiàn)Bean的初始化和銷毀的方式

 更新時間:2025年05月07日 08:43:11   作者:攢了一袋星辰  
這篇文章主要介紹了Spring實現(xiàn)Bean的初始化和銷毀的方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

在前面的章節(jié)當中介紹完畢了ApplicationContext,也就是應(yīng)用上下文。我們說BeanFactory是面向開發(fā)者的,ApplicationContext才是面向使用者的,實際上也是如此。在ApplicationContest當中我們對BeanFactory進行了進一步的集成,實現(xiàn)了自動化的XML文件讀取,注冊BeanFacoryPostProcess,注冊BeanPostProcess,以及提前初始化單列Bean。

以上都是屬于Bean生命周期的一部分,是通過Spring自動管理的,除此之外Spring還允許用戶自定義初始化與銷毀方法,同樣也可以通過Spring自動化調(diào)用。

一、Bean的初始化

在實現(xiàn)初始化與銷毀之前我們需要先考慮一下什么時候進行初始化,什么時候要銷毀。

很簡單,初始化發(fā)生在創(chuàng)建Bean的時候,而銷毀發(fā)生在容器或者虛擬機關(guān)閉的時候。那么對于初始化來說他是針對對應(yīng)的Bean的,也就是說在創(chuàng)建的時候執(zhí)行,而銷毀是一個統(tǒng)一的行為,當容器關(guān)閉時候需要對指定Bean進行統(tǒng)一的銷毀。

那么明白了上述邏輯后我們就開始我們的邏輯實現(xiàn)

首先容器的初始化行為是正對Bean本身,實際上和BeanPostProcessor非常類似,只不過初始化的行為更具象罷了。

首先我們需要在BeanDefinition當中添加初始化的方法名,該名稱用于用戶通過XML/注解方式自定義初始化的方法

private String initMethodName;

第二步,定義用于初始化的父類,這樣我們的Bean就可以集成該類,重寫初始化方法。

public interface InitializingBean {  
    void afterPropertiesSet();  
}

現(xiàn)在再回到AbstractAutowireCapableBeanFactory當中的初始化方法initializeBean當中,在這里執(zhí)行完了BeanPostProcess的前置增強之后,執(zhí)行用戶定義的初始化方法。

private void initializeBean(String beanName, Object bean,BeanDefinition beanDefinition) {  
    // 執(zhí)行初始化之前的BeanPostProcessor前置處理  
    Object wrappedBean  = applyBeanPostProcessorsBeforeInitialization(bean, beanName);  
  
    // 執(zhí)行初始化方法  
    try {  
        invokeInitMethods(beanName , wrappedBean , beanDefinition);  
    } catch (Exception e) {  
        throw new BeansException("調(diào)用 bean 的 init 方法[" + beanName + "] 失敗", e);  
    }  
  
    // 執(zhí)行初始化之前的BeanPostProcessor后置  
    wrappedBean = applyBeanPostProcessorsAfterInitialization(bean , beanName);  
}

初始化的邏輯也很簡單,首先判斷用戶是否實現(xiàn)了InitializingBean這個接口,如果實現(xiàn)了則調(diào)用其重寫的afterPropertiesSet初始化方法。之后再判斷用戶是否是自己指定了自定義的初始化方法,如果指定則通過反射獲取到該方法并執(zhí)行即可。

private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception{  
    if (bean instanceof InitializingBean){  
        ((InitializingBean) bean).afterPropertiesSet();  
    }  
  
    // 處理用戶自定義的初始化方法  
    if (StrUtil.isNotEmpty(beanDefinition.getInitMethodName())){  
        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的銷毀相對于初始化來說最大的區(qū)別在于,初始化時正對單個Bean,銷毀是針對所有要銷毀的Bean。

也就是說,我們需要定一個Map集合存儲所有要銷毀的Bean,在容器關(guān)閉時遍歷集合,執(zhí)行其銷毀方法。

首先我們需要在BeanDefinition當中添加銷毀的方法名,該名稱用于用戶通過XML/注解方式自定義銷毀的方法

private String destroyMethodName;

第二步,定義用于銷毀的父類,這樣我們的Bean就可以集成該類,重寫銷毀方法。

public interface DisposableBean {  
  
    public void destroy();  
}

然后我們需要回到ConfigurableApplicationContext,因為實際上Bean的銷毀時應(yīng)用上下文的行為,在我們關(guān)閉ApplicationContext的時候才會執(zhí)行。

public interface ConfigurableApplicationContext extends ApplicationContext {  
    /**  
     * 刷新容器,重新加載并初始化所有配置和Bean  
     */    
    void refresh();  
  
    /**  
     * 關(guān)閉ApplicationContext  
     */    
    void close();  
  
  
    void registerShutdownHook();  
}

在AbstractApplicationContext實現(xiàn)這些方法,先看下面的代碼,這里可能會有一個疑問就是getBeanFactory().destroySingletons(); 通過完整的代碼我們可以知道getBeanFactory()返回的是一個DefaultListableBeanFactory的對象,那么我們也要在其父類當中實現(xiàn)該方法。

/**  
 * 關(guān)閉ApplicationContext  
 */@Override  
public void close() {  
    doClose();  
}  
  
private void doClose() {  
    destroyBeans();  
  
}  
  
private void destroyBeans() {  
    getBeanFactory().destroySingletons();  
}  
  
@Override  
public void registerShutdownHook() {  
    Thread shutdownHook = new Thread(this::doClose);  
    Runtime.getRuntime().addShutdownHook(shutdownHook);  
}

首先我們要明確一點,在Spring當中所有接口都被指責(zé)化了,也就是說不同接口有著不同的功能,而Bean的銷毀也屬于單列Bean的生命周期當中,所以我們要在DefaultSingletonBeanRegistry當中實現(xiàn)該方法,除此之外destroySingletons該方法我們還需要在ConfigurableBeanFactory當中定義。

其中ConfigurableBeanFactory與DefaultSingletonBeanRegistry之間都繼承于SingletonBeanRegistry,但是我們不在SingletonBeanRegistry當中定義destroySingletons接口,二者時通過組合繼承實現(xiàn)的

public void destroySingletons(){  
    Set<String> beanNames = disposableBeans.keySet();  
    for (String beanName : beanNames) {  
        DisposableBean disposableBean = disposableBeans.remove(beanName);  
        // 執(zhí)行銷毀方法  
        disposableBean.destroy();  
    }  
  
}
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {  
  
    /**  
     * 添加一個 BeanPostProcessor 到工廠中。  
     * BeanPostProcessor 可以在 Bean 初始化前后執(zhí)行自定義邏輯。  
     *  
     * @param beanPostProcessor 要添加的 BeanPostProcessor 實例  
     */  
    void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);  
  
  
    /**  
     * 銷毀單例bean  
     */    
    void destroySingletons();  
}

其實到這里所有的邏輯就結(jié)束了,下面寫一個測試

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;  
    }  
  
    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() {  
        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();  
    }  
}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中Map與JSON數(shù)據(jù)之間的互相轉(zhuǎn)化

    Java中Map與JSON數(shù)據(jù)之間的互相轉(zhuǎn)化

    我們在開發(fā)中難免和JSON打交道,這不小編最近遇到了,需要把一些信息轉(zhuǎn)成JSON字符串,下面這篇文章主要給大家介紹了關(guān)于Java中Map與JSON數(shù)據(jù)之間的互相轉(zhuǎn)化,需要的朋友可以參考下
    2023-04-04
  • mac配置idea maven全過程

    mac配置idea maven全過程

    本文主要介紹了在Mac上配置IDEA和Maven的過程,包括下載Maven、編輯setting.xml文件、配置Maven和IDEA的相關(guān)路徑等步驟
    2026-04-04
  • SpringBoot基礎(chǔ)框架詳解

    SpringBoot基礎(chǔ)框架詳解

    SpringBoot開發(fā)目的是為了簡化Spring應(yīng)用的創(chuàng)建、運行、調(diào)試和部署等,使用Spring Boot可以不用或者只需要很少的Spring配置就可以讓企業(yè)項目快速運行起來,本文介紹SpringBoot基礎(chǔ)框架詳解,感興趣的朋友一起看看吧
    2025-05-05
  • Java如何獲取HttpServletRequest請求參數(shù)

    Java如何獲取HttpServletRequest請求參數(shù)

    我們常需要接口接收第三方推送的數(shù)據(jù),由于第三方可能不具備開發(fā)能力,我們需要自行解析推送的數(shù)據(jù)格式,通過HttpServletRequest,我們可以解析字符串、JSON、XML以及文件等多種數(shù)據(jù)類型,本文介紹了如何在Java中使用HttpServletRequest獲取請求參數(shù),感興趣的朋友一起看看吧
    2024-11-11
  • Hibernate的延遲加載的項目實踐

    Hibernate的延遲加載的項目實踐

    Hibernate延遲加載(Lazy Loading)是一種性能優(yōu)化技術(shù),僅在需要時加載關(guān)聯(lián)數(shù)據(jù),減少初始查詢和內(nèi)存消耗,本文就來介紹一下Hibernate 延遲加載的實現(xiàn),感興趣的可以了解一下
    2026-01-01
  • java多線程抓取鈴聲多多官網(wǎng)的鈴聲數(shù)據(jù)

    java多線程抓取鈴聲多多官網(wǎng)的鈴聲數(shù)據(jù)

    很容易就能發(fā)現(xiàn)通過改變 listId和page就能從服務(wù)器獲取鈴聲的json數(shù)據(jù), 通過解析json數(shù)據(jù), 可以看到都帶有{"hasmore":1,"curpage":1}這樣子的指示,通過判斷hasmore的值,決定是否進行下一頁的抓取。 但是通過上面這個鏈接返回的json中不帶有鈴聲的下載地址
    2016-04-04
  • Java導(dǎo)出多個excel表打包到zip文件中供客戶端另存為窗口下載實現(xiàn)方法

    Java導(dǎo)出多個excel表打包到zip文件中供客戶端另存為窗口下載實現(xiàn)方法

    最近的項目有一個導(dǎo)出匯總數(shù)據(jù)的要求,考慮到用戶軟件的差異,所以要分別導(dǎo)出xls以及xlsx并且打包提供下載,下面這篇文章主要給大家介紹了關(guān)于Java導(dǎo)出多個excel表打包到zip文件中供客戶端另存為窗口下載的實現(xiàn)方法,需要的朋友可以參考下
    2023-12-12
  • SpringBoot中的Ajax和MyBatis究竟是什么

    SpringBoot中的Ajax和MyBatis究竟是什么

    本文深入解析了Spring Boot項目中Ajax與MyBatis的核心作用及協(xié)作機制,Ajax作為前端異步通信引擎,通過axios等庫實現(xiàn)無刷新數(shù)據(jù)交互,本文給大家介紹SpringBoot中的Ajax和MyBatis究竟是什么,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • SpringCloud?Feign實現(xiàn)微服務(wù)之間相互請求問題

    SpringCloud?Feign實現(xiàn)微服務(wù)之間相互請求問題

    Feign是Netflix開發(fā)的聲明式、模板化的HTTP客戶端,?Feign可以幫助我們更快捷、優(yōu)雅地實現(xiàn)微服務(wù)之間的調(diào)用,這篇文章主要介紹了SpringCloud?Feign實現(xiàn)微服務(wù)之間相互請求,需要的朋友可以參考下
    2022-06-06
  • Java可執(zhí)行JAR包打包三種方式完全解析

    Java可執(zhí)行JAR包打包三種方式完全解析

    在Java開發(fā)中我們經(jīng)常使用JAR文件來打包應(yīng)用程序及其依賴,這個過程涉及到許多細節(jié),尤其是在項目中包含其他JAR文件時,這篇文章主要介紹了Java可執(zhí)行JAR包打包三種方式完全解析的相關(guān)資料,需要的朋友可以參考下
    2026-05-05

最新評論

潞西市| 德昌县| 景德镇市| 芮城县| 衡阳市| 瑞丽市| 丁青县| 大石桥市| 开江县| 革吉县| 宁蒗| 永春县| 墨竹工卡县| 雅安市| 桑日县| 英山县| 烟台市| 连江县| 闵行区| 准格尔旗| 通化市| 专栏| 曲松县| 平邑县| 吉林省| 岳池县| 准格尔旗| 定边县| 县级市| 南乐县| 卓资县| 和政县| 新邵县| 中西区| 洛宁县| 新昌县| 巴马| 新津县| 高碑店市| 阳西县| 邢台市|