前言
本系列前面講解了Spring的bean定義、bean實體化、bean初始化等生命周期,這些步驟使我們能夠了解bean從創建到準備好使用所經歷的程序,但是,除了這些步驟,bean的銷毀也是非常重要的一步,在本系列的最后,我們將深入探討bean的銷毀程序,包括在什么情況下會發生銷毀、銷毀的順序以及如何在bean銷毀之前執行一些清理任務等,通過學習bean的銷毀程序,我們將更全面地了解Spring的bean生命周期,
在Spring中,有多種方式可以銷毀bean,其中一種方式是在應用程式關閉時顯式地呼叫applicationContext.close()
方法來關閉容器,這個方法將會銷毀所有還沒有被銷毀的bean,
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
applicationContext.close();
實作DisposableBean介面
實作DisposableBean介面是一種銷毀bean的簡單方式,當bean容器關閉時,Spring會呼叫DisposableBean的destroy()方法來銷毀bean,以下是一些示例代碼:
import org.springframework.beans.factory.DisposableBean;
@Component
public class MyBean implements DisposableBean {
@Override
public void destroy() throws Exception {
// 在這里清理資源
}
}
使用@PreDestroy注解
使用@PreDestroy注解是另一種簡單的方式來銷毀bean,當bean容器關閉時,Spring會呼叫使用@PreDestroy注解的方法來銷毀bean,以下是一些示例代碼:
import javax.annotation.PreDestroy;
@Component
public class MyBean {
@PreDestroy
public void cleanUp() throws Exception {
// 在這里清理資源
}
}
registerDisposableBeanIfNecessary
registerDisposableBeanIfNecessary()
方法是一個非常重要的方法,它是在bean創建后進行處理bean銷毀邏輯的前提,在Spring的AbstractBeanFactory
類中,該方法會檢查當前bean是否實作了DisposableBean
介面或者@PreDestroy
注解,如果是的話,就會將該bean添加到一個DisposableBeanAdapter
物件中,該物件會在bean銷毀時被呼叫以執行銷毀任務,這個程序是在bean銷毀之前執行的,以確保正確關閉應用程式,
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
}
}
我大概講下這個方法requiresDestruction
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
bean, getBeanPostProcessorCache().destructionAware))));
}
- DisposableBeanAdapter.hasDestroyMethod:校驗是否實作了DisposableBean或者AutoCloseable介面,如果沒有的話,再查看是否bean定義的destroyMethodName屬性是
(inferred)
,如果是的話,那么直接找這個類是否有close方法沒有的話再找shutdown方法 - DisposableBeanAdapter.hasApplicableProcessors:是否有@PreDestroy注解
DisposableBeanAdapter
DisposableBeanAdapter
物件是一個配接器,用于在銷毀bean時執行必要的處理,它會將DisposableBean
介面或@PreDestroy
注解的方法轉換為一個回呼方法,以便在bean銷毀時執行,這種配接器模式允許非標準的bean銷毀方法與Spring框架協同作業,
在將DisposableBeanAdapter
物件添加到一個DisposableBeanRegistry
物件中時,Spring會將該物件添加到一個bean銷毀的注冊表中,當需要銷毀所有bean時,Spring就會從該注冊表中獲取所有需要銷毀的bean,并按照正確的順序執行銷毀任務,這樣就可以確保應用程式的正確關閉,
destroySingleton
當Spring程式關閉時,會呼叫destroyBeans
方法,這里我們分析關鍵部分代碼:
public void destroySingleton(String beanName) {
// Remove a registered singleton of the given name, if any.
// 先從單例池中移除掉
removeSingleton(beanName);
// Destroy the corresponding DisposableBean instance.
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
}
destroyBean(beanName, disposableBean);
}
- removeSingleton:先從單例池中移除掉
- this.disposableBeans.remove:這里回傳的是我們之前呼叫registerDisposableBeanIfNecessary方法添加進去的DisposableBeanAdapter配接器
- destroyBean:直接銷毀bean,這里注意一個小點就是如果當前bean被其他bean依賴了,那么先移除銷毀其他Bean,然后就是呼叫配接器的destroy方法
總結
非常感謝您對 Spring 生命周期系列文章的關注和支持,我們在過去一個月中深入了解了 Spring 框架中 Bean 的生成、初始化、后置處理和銷毀等程序,對于理解 Spring 框架的原理和機制非常有幫助,我們總結一下Spring到底做了那些事情將bean從生成到銷毀的全程序:
- 專案啟動時,ClassPathBeanDefinitionScanner掃描得到所有BeanDefinition,由于ACM技術所以此時beanclass屬性為String型別的bean的名稱
- 獲取合并后的BeanDefinition
- beanClass開始真正的被加載替換原有String型別的bean的名稱
- 呼叫實體化前處理方法applyBeanPostProcessorsBeforeInstantiation
- 通過構造方法創建Bean實體
- 后置處理合并后的BeanDefinition,呼叫postProcessMergedBeanDefinition(尋找注入點)
- 呼叫實體化后處理方法postProcessAfterInstantiation
- 開始進行屬性注入:postProcessProperties
- 呼叫初始化前處理方法:applyBeanPostProcessorsBeforeInitialization
- 進行初始化:invokeInitMethods,會呼叫指定init方法或者afterPropertiesSet方法
- 呼叫初始化后處理方法:applyBeanPostProcessorsAfterInitialization(AOP)
- 容器關閉時,走bean的銷毀邏輯,即今天所講
這里面有很多邏輯流程我都在單獨的文章中有細講,比如FactoryBean、PropertyValues等等,由于是總結所以就不全寫出來了,也希望大家可以好好理解Spring原始碼,下一步,我們將會著重講解 Bean 的屬性依賴注入,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553194.html
標籤:Java
上一篇:java IO流
下一篇:返回列表