網(wǎng)站首頁 編程語言 正文
詳解Spring Bean的生命周期
Spring Bean的生命周期包括以下階段:
1. 實例化Bean
對于BeanFactory容器,當(dāng)客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調(diào)用createBean進行實例化。 對于ApplicationContext容器,當(dāng)容器啟動結(jié)束后,便實例化所有的bean。 容器通過獲取BeanDefinition對象中的信息進行實例化。并且這一步僅僅是簡單的實例化,并未進行依賴注入。 實例化對象被包裝在BeanWrapper對象中,BeanWrapper提供了設(shè)置對象屬性的接口,從而避免了使用反射機制設(shè)置屬性。
2. 設(shè)置對象屬性(依賴注入)
實例化后的對象被封裝在BeanWrapper對象中,并且此時對象仍然是一個原生的狀態(tài),并沒有進行依賴注入。 緊接著,Spring根據(jù)BeanDefinition中的信息進行依賴注入。 并且通過BeanWrapper提供的設(shè)置屬性的接口完成依賴注入。
3. 注入Aware接口
緊接著,Spring會檢測該對象是否實現(xiàn)了xxxAware接口,并將相關(guān)的xxxAware實例注入給bean。
4. BeanPostProcessor
當(dāng)經(jīng)過上述幾個步驟后,bean對象已經(jīng)被正確構(gòu)造,但如果你想要對象被使用前再進行一些自定義的處理,就可以通過BeanPostProcessor接口實現(xiàn)。 該接口提供了兩個函數(shù):postProcessBeforeInitialzation( Object bean, String beanName ) 當(dāng)前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。 這個函數(shù)會先于InitialzationBean執(zhí)行,因此稱為前置處理。 所有Aware接口的注入就是在這一步完成的。postProcessAfterInitialzation( Object bean, String beanName ) 當(dāng)前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。 這個函數(shù)會在InitialzationBean完成后執(zhí)行,因此稱為后置處理。
5. InitializingBean與init-method
當(dāng)BeanPostProcessor的前置處理完成后就會進入本階段。 InitializingBean接口只有一個函數(shù):afterPropertiesSet()這一階段也可以在bean正式構(gòu)造完成前增加我們自定義的邏輯,但它與前置處理不同,由于該函數(shù)并不會把當(dāng)前bean對象傳進來,因此在這一步?jīng)]辦法處理對象本身,只能增加一些額外的邏輯。 若要使用它,我們需要讓bean實現(xiàn)該接口,并把要增加的邏輯寫在該函數(shù)中。然后Spring會在前置處理完成后檢測當(dāng)前bean是否實現(xiàn)了該接口,并執(zhí)行afterPropertiesSet函數(shù)。當(dāng)然,Spring為了降低對客戶代碼的侵入性,給bean的配置提供了init-method屬性,該屬性指定了在這一階段需要執(zhí)行的函數(shù)名。Spring便會在初始化階段執(zhí)行我們設(shè)置的函數(shù)。init-method本質(zhì)上仍然使用了InitializingBean接口。
6. DisposableBean和destroy-method
和init-method一樣,通過給destroy-method指定函數(shù),就可以在bean銷毀前執(zhí)行指定的邏輯。
詳解Spring Bean生命周期
Spring Bean的完整生命周期從創(chuàng)建Spring容器開始,直到最終Spring容器銷毀Bean,這其中包含了一系列關(guān)鍵點。
例子演示
我們用一個簡單的Spring Bean來演示一下Spring Bean的生命周期。
1.首先是一個簡單的Spring Bean,調(diào)用Bean自身的方法和Bean級生命周期接口方法,為了方便演示,它實現(xiàn)了BeanNameAware
、BeanFactoryAware
、InitializingBean
和DiposableBean
這4個接口,同時有2個方法,對應(yīng)配置文件中的init-method和destroy-method。如下:
package springBeanTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* @author qsk
*/
public class Person implements BeanFactoryAware, BeanNameAware,
InitializingBean, DisposableBean {
private String name;
private String address;
private int phone;
private BeanFactory beanFactory;
private String beanName;
public Person() {
System.out.println("【構(gòu)造器】調(diào)用Person的構(gòu)造器實例化");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("【注入屬性】注入屬性name");
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
System.out.println("【注入屬性】注入屬性address");
this.address = address;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
System.out.println("【注入屬性】注入屬性phone");
this.phone = phone;
}
@Override
public String toString() {
return "Person [address=" + address + ", name=" + name + ", phone="
+ phone + "]";
}
// 這是BeanFactoryAware接口方法
@Override
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out
.println("【BeanFactoryAware接口】調(diào)用BeanFactoryAware.setBeanFactory()");
this.beanFactory = arg0;
}
// 這是BeanNameAware接口方法
@Override
public void setBeanName(String arg0) {
System.out.println("【BeanNameAware接口】調(diào)用BeanNameAware.setBeanName()");
this.beanName = arg0;
}
// 這是InitializingBean接口方法
@Override
public void afterPropertiesSet() throws Exception {
System.out
.println("【InitializingBean接口】調(diào)用InitializingBean.afterPropertiesSet()");
}
// 這是DiposibleBean接口方法
@Override
public void destroy() throws Exception {
System.out.println("【DiposibleBean接口】調(diào)用DiposibleBean.destory()");
}
// 通過<bean>的init-method屬性指定的初始化方法
public void myInit() {
System.out.println("【init-method】調(diào)用<bean>的init-method屬性指定的初始化方法");
}
// 通過<bean>的destroy-method屬性指定的初始化方法
public void myDestory() {
System.out.println("【destroy-method】調(diào)用<bean>的destroy-method屬性指定的初始化方法");
}
}
2.接下來是演示BeanPostProcessor接口的方法,如下:
package springBeanTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
super();
System.out.println("這是BeanPostProcessor實現(xiàn)類構(gòu)造器?。?);
// TODO Auto-generated constructor stub
}
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
System.out
.println("BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!");
return arg0;
}
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
System.out
.println("BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!");
return arg0;
}
}
如上,BeanPostProcessor接口包括2個方法postProcessAfterInitialization
和postProcessBeforeInitialization
,這兩個方法的第一個參數(shù)都是要處理的Bean對象,第二個參數(shù)都是Bean的name。返回值也都是要處理的Bean對象。這里要注意。
3、InstantiationAwareBeanPostProcessor 接口本質(zhì)是BeanPostProcessor的子接口,一般我們繼承Spring為其提供的適配器類InstantiationAwareBeanPostProcessorAdapter來使用它,如下:
package springBeanTest;
import java.beans.PropertyDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
public class MyInstantiationAwareBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter {
public MyInstantiationAwareBeanPostProcessor() {
super();
System.out
.println("這是InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類構(gòu)造器??!");
}
// 接口方法、實例化Bean之前調(diào)用
@Override
public Object postProcessBeforeInstantiation(Class beanClass,
String beanName) throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor調(diào)用postProcessBeforeInstantiation方法");
return null;
}
// 接口方法、實例化Bean之后調(diào)用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor調(diào)用postProcessAfterInitialization方法");
return bean;
}
// 接口方法、設(shè)置某個屬性時調(diào)用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor調(diào)用postProcessPropertyValues方法");
return pvs;
}
}
這個有3個方法,其中第二個方法postProcessAfterInitialization
就是重寫了BeanPostProcessor的方法。第三個方法postProcessPropertyValues
用來操作屬性,返回值也應(yīng)該是PropertyValues對象。
4.演示工廠后處理器接口方法,如下:
package springBeanTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
super();
System.out.println("這是BeanFactoryPostProcessor實現(xiàn)類構(gòu)造器??!");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws BeansException {
System.out
.println("BeanFactoryPostProcessor調(diào)用postProcessBeanFactory方法");
BeanDefinition bd = arg0.getBeanDefinition("person");
bd.getPropertyValues().addPropertyValue("phone", "110");
}
}
5.配置文件如下beans.xml,很簡單,使用ApplicationContext,處理器不用手動注冊:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">
</bean>
<bean id="instantiationAwareBeanPostProcessor" class="springBeanTest.MyInstantiationAwareBeanPostProcessor">
</bean>
<bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">
</bean>
<bean id="person" class="springBeanTest.Person" init-method="myInit"
destroy-method="myDestory" scope="singleton" p:name="張三" p:address="廣州"
p:phone="15900000000" />
</beans>
6.下面測試一下:
package springBeanTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCycle {
public static void main(String[] args) {
System.out.println("現(xiàn)在開始初始化容器");
ApplicationContext factory = new ClassPathXmlApplicationContext("springBeanTest/beans.xml");
System.out.println("容器初始化成功");
//得到Preson,并使用
Person person = factory.getBean("person",Person.class);
System.out.println(person);
System.out.println("現(xiàn)在開始關(guān)閉容器!");
((ClassPathXmlApplicationContext)factory).registerShutdownHook();
}
}
我們來看一下結(jié)果:
現(xiàn)在開始初始化容器
2014-5-18 15:46:20 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@19a0c7c: startup date [Sun May 18 15:46:20 CST 2014]; root of context hierarchy
2014-5-18 15:46:20 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springBeanTest/beans.xml]
這是BeanFactoryPostProcessor實現(xiàn)類構(gòu)造器!!
BeanFactoryPostProcessor調(diào)用postProcessBeanFactory方法
這是BeanPostProcessor實現(xiàn)類構(gòu)造器?。?這是InstantiationAwareBeanPostProcessorAdapter實現(xiàn)類構(gòu)造器??!
2014-5-18 15:46:20 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@9934d4: defining beans [beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor,person]; root of factory hierarchy
InstantiationAwareBeanPostProcessor調(diào)用postProcessBeforeInstantiation方法
【構(gòu)造器】調(diào)用Person的構(gòu)造器實例化
InstantiationAwareBeanPostProcessor調(diào)用postProcessPropertyValues方法
【注入屬性】注入屬性address
【注入屬性】注入屬性name
【注入屬性】注入屬性phone
【BeanNameAware接口】調(diào)用BeanNameAware.setBeanName()
【BeanFactoryAware接口】調(diào)用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!
【InitializingBean接口】調(diào)用InitializingBean.afterPropertiesSet()
【init-method】調(diào)用<bean>的init-method屬性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!
InstantiationAwareBeanPostProcessor調(diào)用postProcessAfterInitialization方法
容器初始化成功
Person [address=廣州, name=張三, phone=110]
現(xiàn)在開始關(guān)閉容器!
【DiposibleBean接口】調(diào)用DiposibleBean.destory()
【destroy-method】調(diào)用<bean>的destroy-method屬性指定的初始化方法
Spring Bean生命周期流程圖
原文鏈接:https://blog.csdn.net/Mr_VK/article/details/132090604
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2022-12-13 Python使用Matplotlib繪制三維散點圖詳解流程_python
- 2022-09-14 利用Pandas實現(xiàn)對數(shù)據(jù)進行移動計算_python
- 2023-02-25 Golang嵌入資源文件實現(xiàn)步驟詳解_Golang
- 2022-11-28 一文帶你搞懂Golang結(jié)構(gòu)體內(nèi)存布局_Golang
- 2023-07-05 讓Linux中的SCP遠(yuǎn)程復(fù)制不再需要輸入密碼
- 2022-11-23 pytorch?tensorboard可視化的使用詳解_python
- 2022-07-24 .Net結(jié)構(gòu)型設(shè)計模式之享元模式(Flyweight)_基礎(chǔ)應(yīng)用
- 2023-10-09 instanceof` 的基本工作原理
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支