生命週期流程
- 1~2創建實例。創建實例就是:這裏就是把配置文件中的bean信息化作一個bean讀取到容器裏面
- 3~4是注入依賴關係,3是對bean實例化之後做一些操作,4是配置文件中的bean屬性設置到bean中
- 5是bean初始化之前的處理,應用開發者需要把容器中實例化的bean拿出來用,這個拿出來的過程就是初始化注意實例化與初始化的區別,instantiation 和initialization
- 6~7 如果bean實現了InitializingBean,那麼將調用InitializingBean的afterPropertiesSet()方法做一些初始化處理。如果沒有實現InitializingBean,而是在配置文件中定義了init-method屬性值,那麼系統會找到init-method對應的方法並執行之,一般在這個方法裏寫一些初始化操作
- 8是初始化之後的操作,可以在初始化後進行一些修飾
- 9~10是交給應用開發者使用,如果在中指定Bean的作用範圍是scopt=“prototype”,那麼系統將bean返回給調用者,spring就不管了(如果兩個實例調用的話,每一次調用都要重新初始化,一個實例的修改不會影響另一個實例的值。如果指定Bean的作用範圍是scope=“singleton”,則把bean放到緩衝池中,並將bean的引用返回給調用者。這個時候,如果兩個實例調用的話,因爲它們用的是同一個引用,任何一方的修改都會影響到另一方。)
- 11是bean用完之後,對於scope="singleton"的bean,使用完之後spring容器會做一些處理,比如編寫釋放資源、記錄日誌等操作。
- 12是配置文件中自己配置的銷燬方法
舉個栗子🌰
applicationContext.xml是bean的一個配置類
<?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:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="eason" class="person.shw.spring.sourcecode.pojo.Eason" init-method="myInit" destroy-method="myDestory" scope="singleton">
<property name="girlFriend" value="還沒有女朋友"/>
<property name="profession" value="歌手"/>
<property name="sex" value="男"/>
</bean>
</beans>
MyInstantiationAwareBeanPostProcessor.java配置增強類
package person.shw.spring.sourcecode.inistantiation;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import person.shw.spring.sourcecode.pojo.Eason;
import java.beans.PropertyDescriptor;
/**
* @author shihaowei
* @date 2020-06-15 18:12
*/
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("eason")){
System.err.println("MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation");
}
return null;
}
/**
* 實例化bean後的增強修飾
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("eason")){
System.err.println("MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation");
}
return true;
}
/**
* 把配置文件值複製給屬性
* @param pvs
* @param pds
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
if (beanName.equals("eason")){
Eason eason = (Eason)bean;
System.err.println("MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues");
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
上面的類是繼承了InstantiationAwareBeanPostProcessorAdopter的,而InstantiationAwareBeanPostProcessorAdopter這個適配器與是InstantiationAwareBeanPostProcessor的擴展類。
public class MyBeanPostProcessor implements BeanPostProcessor {
Log log = LogFactory.getLog(MyBeanPostProcessor.class);
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("eason")) {
Eason eason = (Eason) bean;
log.info("配置文件中eason的女朋友是:"+eason.getGirlFriend());
eason.setGirlFriend("楊千嬅");
log.info("調用BeanPostProcessor的postProcessBeforeInitialization處理後," +
"eason的女朋友變爲:"+eason.getGirlFriend());
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("eason")) {
Eason eason = (Eason)bean;
log.info("eason當前的女朋友是:"+eason.getGirlFriend());
eason.setGirlFriend("徐濠縈");
log.info("調用BeanPostProcessor的postProcessAfterInitialization處理後," +
"eason的女朋友變成:"+eason.getGirlFriend());
}
return bean;
}
}
上面的代碼實現了BeanPostProcessor。InstantiationAwareBeanPostProcessor是實例化前後做的事情,BeanPostProcessor是初始化前後做的事情,它們之間應該存在着父子關係吧?當然是,從名字就能看出來前者是後者的擴展類,讀者可以自己下載spring源碼查看。這兩個類定義好了需要註冊才能使用(把它們註冊到spring容器中使用),稍後再講。這裏先講bean類:
/**
* @author shihaowei
* @date 2020-06-15 16:57
*/
public class Eason implements InitializingBean, DisposableBean {
Log log = LogFactory.getLog(Eason.class);
private String sex;
private String profession;
private String girlFriend;
public Eason() {
log.info("調用Eason默認無參構造函數,Eason出道了");
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public String getGirlFriend() {
return girlFriend;
}
public void setGirlFriend(String girlFriend) {
this.girlFriend = girlFriend;
}
public void myInit(){
this.girlFriend = "eason正在追徐濠縈";
log.info("通過調用配置文件初始化女朋友爲:"+this.girlFriend);
}
public void myDestory(){
log.info("調用myDestory()");
}
public void destroy() throws Exception {
log.info("調用DisposableBean.destory(),銷燬");
}
public void afterPropertiesSet() throws Exception {
this.profession = "歌手";
log.info("調用InitializingBean.afterPropertiesSet()," +
"屬性配置完畢了再做些善後工作。");
}
@Override
public String toString() {
return "Eason{" +
"sex='" + sex + '\'' +
", profession='" + profession + '\'' +
", girlFriend='" + girlFriend + '\'' +
'}';
}
}
這個bean實現了InitializingBean,DisposableBean,那麼第六步和第11步就可以用得到了,下面是註冊和測試方法:
public class BeanLifeCycleMain {
private static Log log= LogFactory.getLog(BeanLifeCycleMain.class);
private static void lifeCycleInBeanFactory(){
Resource resource = new ClassPathResource("applicationContext.xml");
啓動一個xml的容器
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
// 這裏是註冊事件
((ConfigurableBeanFactory)beanFactory).addBeanPostProcessor(new MyBeanPostProcessor());
((ConfigurableBeanFactory)beanFactory).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
Eason eason = (Eason) beanFactory.getBean("eason");
log.info("eason:"+eason.toString());
//((XmlBeanFactory)beanFactory).destroySingletons();
Eason eason2 = (Eason) beanFactory.getBean("eason");
eason2.setGirlFriend("楊千嬅");
log.info("eason2:"+eason2.toString());
log.info("eason:"+eason.toString());
log.info(eason == eason2);
}
public static void main(String[] args) {
lifeCycleInBeanFactory();
}
}
下面我們看一下日誌結果
MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason <init>
信息: 調用Eason默認無參構造函數,Eason出道了
MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 配置文件中eason的女朋友是:還沒有女朋友
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 調用BeanPostProcessor的postProcessBeforeInitialization處理後,eason的女朋友變爲:楊千嬅
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason afterPropertiesSet
信息: 調用InitializingBean.afterPropertiesSet(),屬性配置完畢了再做些善後工作。
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason myInit
信息: 通過調用配置文件初始化女朋友爲:eason正在追徐濠縈
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: eason當前的女朋友是:eason正在追徐濠縈
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: 調用BeanPostProcessor的postProcessAfterInitialization處理後,eason的女朋友變成:徐濠縈
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='徐濠縈'}
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason2:Eason{sex='男', profession='歌手', girlFriend='楊千嬅'}
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='楊千嬅'}
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: true
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason destroy
信息: 調用DisposableBean.destory(),銷燬
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason myDestory
信息: 調用myDestory()
行1:實例化之前處理了一些事情。
行2~3:duang!開始實例化,實例化當然首先要執行構造函數(這是美好世界的窗口)。
行4:實例化之後處理了一些事情。
行5:實例化之後注入屬性值之前要調用這個函數。
行6~7:注入xml的屬性值,可以看到是配置中的"還沒有女朋友"。
行8~9:注入屬性值後,隨即又把女朋友這個屬性的值改爲了"楊千嬅"。
行10~11:屬性配置完畢了做一些善後工作。在Eason類我把職業改爲了"歌手",所以後面顯示的職業都是"歌手",而不是配置文件中的"歌手,演員,導演,主持"。
行12~13:調用了配置文件中的init-method。通過的class屬性找到這個類,再找到屬性值對應的這個方法執行。但是實現必須implements InitializingBean,給代碼帶來複雜度和污染。
行14和行17是初始化之後做的事情,首先顯示當前女朋友,又把女朋友改爲了徐濠縈。
行18-行25:看對應的代碼就會發現,兩個對象其實引用的是同一個地址,eason2修改了屬性之後eason1也會跟着作改變,這就是singleton配置方式的作用。
行26是關閉容器。
行28,一個是調用DisposableBean的銷燬,一個是調用配置文件的銷燬
那麼如果把配置文件的scope屬性改爲"prototype"會發生什麼呢?讓我們看一下打印的日誌:
MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason <init>
信息: 調用Eason默認無參構造函數,Eason出道了
MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 配置文件中eason的女朋友是:還沒有女朋友
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 調用BeanPostProcessor的postProcessBeforeInitialization處理後,eason的女朋友變爲:楊千嬅
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason afterPropertiesSet
信息: 調用InitializingBean.afterPropertiesSet(),屬性配置完畢了再做些善後工作。
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason myInit
信息: 通過調用配置文件初始化女朋友爲:eason正在追徐濠縈
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: eason當前的女朋友是:eason正在追徐濠縈
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: 調用BeanPostProcessor的postProcessAfterInitialization處理後,eason的女朋友變成:徐濠縈
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='徐濠縈'}
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason <init>
信息: 調用Eason默認無參構造函數,Eason出道了
MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 配置文件中eason的女朋友是:還沒有女朋友
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 調用BeanPostProcessor的postProcessBeforeInitialization處理後,eason的女朋友變爲:楊千嬅
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason afterPropertiesSet
信息: 調用InitializingBean.afterPropertiesSet(),屬性配置完畢了再做些善後工作。
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason myInit
信息: 通過調用配置文件初始化女朋友爲:eason正在追徐濠縈
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: eason當前的女朋友是:eason正在追徐濠縈
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: 調用BeanPostProcessor的postProcessAfterInitialization處理後,eason的女朋友變成:徐濠縈
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason2:Eason{sex='男', profession='歌手', girlFriend='楊千嬅'}
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='徐濠縈'}
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: false
當創建eason2對象時,又進行了一次初始化的過程,日誌對比兩個對象爲false,說明兩個對象不同了,這就是prototype的作用。
ApplicationContext中Bean的生命週期與BeanFactory類似,但是又有不同。對於InstantiationAwareBeanPostProcessor和MyBeanPostProcessor,BeanFactory需要在代碼中註冊方纔能使用,而ApplicationContext只需要在xml中配置,spring會自動將它們註冊到應用上下文中,這是二者最大的區別,也是爲什麼普遍使用ApplicationContext而非BeanFactory的原因。ApplicationContext是BeanFactory的擴展類。