網站首頁 編程語言 正文
“請你描述下 Spring Bean 的生命周期?”,這是面試官考察 Spring 的常用問題,可見是 Spring 中很重要的知識點。
其實要記憶該過程,還是需要我們先去理解,本文將從以下兩方面去幫助理解 Bean 的生命周期:
-
生命周期的概要流程:對 Bean 的生命周期進行概括,并且結合代碼來理解;
-
擴展點的作用:詳細介紹 Bean 生命周期中所涉及到的擴展點的作用。
2. 生命周期的概要流程
Bean 的生命周期概括起來就是 4 個階段:
- 實例化(Instantiation)
- 屬性賦值(Populate)
- 初始化(Initialization)
- 銷毀(Destruction)
-
實例化:第 1 步,實例化一個 bean 對象;
-
屬性賦值:第 2 步,為 bean 設置相關屬性和依賴;
-
初始化:第 3~7 步,步驟較多,其中第 5、6 步為初始化操作,第 3、4 步為在初始化前執行,第 7 步在初始化后執行,該階段結束,才能被用戶使用;
-
銷毀:第 8~10步,第8步不是真正意義上的銷毀(還沒使用呢),而是先在使用前注冊了銷毀的相關調用接口,為了后面第9、10步真正銷毀 bean 時再執行相應的方法。
下面我們結合代碼來直觀的看下,在 doCreateBean() 方法中能看到依次執行了這 4 個階段:
// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 實例化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object exposedObject = bean;
try {
// 2. 屬性賦值
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 4. 銷毀-注冊回調接口
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
?由于初始化包含了第 3~7步,較復雜,所以我們進到 initializeBean() 方法里具體看下其過程(注釋的序號對應圖中序號):
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 3. 檢查 Aware 相關接口并設置相關依賴
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 4. BeanPostProcessor 前置處理
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 5. 若實現 InitializingBean 接口,調用 afterPropertiesSet() 方法
// 6. 若配置自定義的 init-method方法,則執行
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 7. BeanPostProceesor 后置處理
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在 invokInitMethods() 方法中會檢查 InitializingBean 接口和 init-method 方法,銷毀的過程也與其類似:
// DisposableBeanAdapter.java
public void destroy() {
// 9. 若實現 DisposableBean 接口,則執行 destory()方法
if (this.invokeDisposableBean) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
}
// 10. 若配置自定義的 detory-method 方法,則執行
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
從 Spring 的源碼我們可以直觀的看到其執行過程,而我們記憶其過程便可以從這 4 個階段出發,實例化、屬性賦值、初始化、銷毀。其中細節較多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。這些都是 Spring 提供的擴展點,其具體作用將在下一節講述。
3. 擴展點的作用
3.1 Aware 接口
若 Spring 檢測到 bean 實現了 Aware 接口,則會為其注入相應的依賴。所以通過讓bean 實現 Aware 接口,則能在 bean 中獲得相應的 Spring 容器資源。
Spring 中提供的 Aware 接口有:
- BeanNameAware:注入當前 bean 對應 beanName;
- BeanClassLoaderAware:注入加載當前 bean 的 ClassLoader;
- BeanFactoryAware:注入 當前BeanFactory容器 的引用。
其代碼實現如下:
// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
以上是針對 BeanFactory 類型的容器,而對于 ApplicationContext 類型的容器,也提供了 Aware 接口,只不過這些 Aware 接口的注入實現,是通過 BeanPostProcessor 的方式注入的,但其作用仍是注入依賴。
- EnvironmentAware:注入 Enviroment,一般用于獲取配置屬性;
- EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于參數解析;
- ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。
其代碼實現如下:
// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
3.2 BeanPostProcessor
BeanPostProcessor 是 Spring 為修改 bean提供的強大擴展點,其可作用于容器中所有 bean,其定義如下:
public interface BeanPostProcessor {
// 初始化前置處理
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 初始化后置處理
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
常用場景有:
- 對于標記接口的實現類,進行自定義處理。例如3.1節中所說的ApplicationContextAwareProcessor,為其注入相應依賴;再舉個例子,自定義對實現解密接口的類,將對其屬性進行解密處理;
- 為當前對象提供代理實現。例如 Spring AOP 功能,生成對象的代理類,然后返回。
// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理類
return proxy;
}
return null;
}
3.3 InitializingBean 和 init-method
InitializingBean 和 init-method 是 Spring 為?bean 初始化提供的擴展點。
InitializingBean接口 的定義如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在 afterPropertiesSet() 方法寫初始化邏輯。
指定 init-method 方法,指定初始化方法:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="demo" class="com.chaycao.Demo" init-method="init()"/>
</beans>
DisposableBean 和 destory-method 與上述類似,就不描述了。
4. 總結
最后總結下如何記憶 Spring Bean 的生命周期:
-
首先是實例化、屬性賦值、初始化、銷毀這 4 個大階段;
-
再是初始化的具體操作,有 Aware 接口的依賴注入、BeanPostProcessor 在初始化前后的處理以及 InitializingBean 和 init-method 的初始化操作;
-
銷毀的具體操作,有注冊相關銷毀回調接口,最后通過DisposableBean 和 destory-method 進行銷毀。
參考鏈接:https://juejin.cn/post/6844904065457979405
?
原文鏈接:https://blog.csdn.net/weixin_56311692/article/details/125776362
相關推薦
- 2022-07-07 ASP.Net使用System.Security.Principal模擬用戶_實用技巧
- 2022-09-01 ASP.NET?Core通用主機實現托管服務_實用技巧
- 2022-04-15 關于pyinstaller生成.exe程序報錯:缺少.ini文件的分析_python
- 2023-08-13 Spring Security 構建基于 JWT 的登錄認證
- 2023-03-04 Google大佬都用的廣播goAsync源碼分析_Android
- 2022-05-22 SQL?Server數據庫基本概念、組成、常用對象與約束_MsSql
- 2022-06-21 C#常用日期時間方法匯總_C#教程
- 2022-05-15 Python獲取網絡圖片和視頻的示例代碼_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支