Version:1.0 StartHTML:000000209 EndHTML:000019387 StartFragment:000001892 EndFragment:000019301 StartSelection:000001892 EndSelection:000019291 SourceURL:https://www.cnblogs.com/5ishare/p/9532057.html <title>Spring之Bean的作用域與生命周期 - 社會主義接班人 - 博客園</title><link href="/bundles/blog-common.css?v=PX31qVjOE47mNaZI9JUSFK-ajuzMnpXA9PeteRNR1Qw1" rel="stylesheet" type="text/css"><link id="MainCss" href="/skins/red_autumnal_leaves/bundle-red_autumnal_leaves.css?v=EDEp2d1uMe8iyN6qDoW8MQgYb-JCFIeiYP0oX3XiiRM1" rel="stylesheet" type="text/css"><link id="mobile-style" href="/skins/red_autumnal_leaves/bundle-red_autumnal_leaves-mobile.css?v=d9LctKHRIQp9rreugMcQ1-UJuq_j1fo0GZXTXj8Bqrk1" rel="stylesheet" type="text/css" media="only screen and (max-width: 767px)"><link title="RSS" rel="alternate" type="application/rss+xml"><link title="RSD" rel="EditURI" type="application/rsd+xml"><link rel="wlwmanifest" type="application/wlwmanifest+xml"> <script type="text/javascript">var currentBlogApp = '5ishare', cb_enable_mathjax=false;var isLogined=true;</script>
在前面博客中提到容器啟動獲得BeanDefinition對象中有一個scope 屬性。該屬性控制著bean對象的作用域。本章節(jié)介紹Bean的作用域及生命周期,了解bean是怎么來的又怎么沒的。
一、Bean的作用域
在Bean容器啟動會讀取bean的xml配置文件,然后將xml中每個bean元素分別轉換成BeanDefinition對象。在BeanDefinition對象中有scope 屬性,就是它控制著bean的作用域。
Spring框架支持5種作用域,有三種作用域是當開發(fā)者使用基于web的ApplicationContext的時候才生效的。下面就是Spring直接支持的作用域了,當然開發(fā)者也可以自己定制作用域。
|
作用域
|
描述
|
|
單例(singleton)
|
(默認)每一個Spring IoC容器都擁有唯一的一個實例對象
|
|
原型(prototype)
|
一個Bean定義,任意多個對象
|
|
請求(request)
|
一個HTTP請求會產(chǎn)生一個Bean對象,也就是說,每一個HTTP請求都有自己的Bean實例。只在基于web的Spring ApplicationContext中可用
|
|
會話(session)
|
限定一個Bean的作用域為HTTPsession的生命周期。同樣,只有基于web的Spring ApplicationContext才能使用
|
|
全局會話(global session)
|
限定一個Bean的作用域為全局HTTPSession的生命周期。通常用于門戶網(wǎng)站場景,同樣,只有基于web的Spring ApplicationContext可用
|
我們可以以XMLInstance類為基礎演示一下singleton和prototype作用域。
這里使用通過BeanFactory的getBean方法獲取兩次bean對象。
<pre> XMLInstance instance=(XMLInstance)factory.getBean("xmlinstance");
instance.setName("123");
instance.Breath();
instance=(XMLInstance)factory.getBean("xmlinstance");
instance.Breath();</pre>
如果我們采用bean默認的作用域singleton,如下配置,則兩個getbean獲取的對象是一致的。
<pre> <bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="singleton">
<property name="air" ref="CleanAir"></property>
<property name="name" value="abc"></property>
</bean></pre>
<pre>輸出結果:
Name:123;Air:CleanAir
Name:123;Air:CleanAir</pre>
如果我們采用bean默認的作用域singleton,如下配置,則兩個getbean獲取的對象是不一致的。
<pre> <bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="prototype">
<property name="air" ref="CleanAir"></property>
<property name="name" value="abc"></property>
</bean></pre>
<pre>輸出結果:
Name:123;Air:CleanAir
Name:abc;Air:CleanAir</pre>
二、Bean的生命周期
前面章節(jié)介紹了bean容器以及bean的配置與注入,本章節(jié)學習bean的生命周期,了解bean是怎么來的又是怎么沒的。

ApplicationContext容器中,Bean的生命周期流程如上圖所示,流程大致如下:
1.首先容器啟動后,會對scope為singleton且非懶加載的bean進行實例化,
2.按照Bean定義信息配置信息,注入所有的屬性,
3.如果Bean實現(xiàn)了BeanNameAware接口,會回調(diào)該接口的setBeanName()方法,傳入該Bean的id,此時該Bean就獲得了自己在配置文件中的id,
4.如果Bean實現(xiàn)了BeanFactoryAware接口,會回調(diào)該接口的setBeanFactory()方法,傳入該Bean的BeanFactory,這樣該Bean就獲得了自己所在的BeanFactory,
5.如果Bean實現(xiàn)了ApplicationContextAware接口,會回調(diào)該接口的setApplicationContext()方法,傳入該Bean的ApplicationContext,這樣該Bean就獲得了自己所在的ApplicationContext,
6.如果有Bean實現(xiàn)了BeanPostProcessor接口,則會回調(diào)該接口的postProcessBeforeInitialzation()方法,
7.如果Bean實現(xiàn)了InitializingBean接口,則會回調(diào)該接口的afterPropertiesSet()方法,
8.如果Bean配置了init-method方法,則會執(zhí)行init-method配置的方法,
9.如果有Bean實現(xiàn)了BeanPostProcessor接口,則會回調(diào)該接口的postProcessAfterInitialization()方法,
10.經(jīng)過流程9之后,就可以正式使用該Bean了,對于scope為singleton的Bean,Spring的ioc容器中會緩存一份該bean的實例,而對于scope為prototype的Bean,每次被調(diào)用都會new一個新的對象,期生命周期就交給調(diào)用方管理了,不再是Spring容器進行管理了
11.容器關閉后,如果Bean實現(xiàn)了DisposableBean接口,則會回調(diào)該接口的destroy()方法,
12.如果Bean配置了destroy-method方法,則會執(zhí)行destroy-method配置的方法,至此,整個Bean的生命周期結束。
這里在UserBean類基礎上進行改造,增加了name屬性并實現(xiàn)了ApplicationContextAware接口。


<pre>package com.demo.model; 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; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class UserBean implements BeanNameAware,BeanFactoryAware,InitializingBean,DisposableBean,ApplicationContextAware { private String name; public String getName() { return name;
} public void setName(String name) { this.name = name;
System.out.println("set方法被調(diào)用");
} public UserBean() {
System.out.println("UserBean類構造方法");
} public void setBeanName(String name) {
System.out.println("BeanNameAware被調(diào)用");
} public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware被調(diào)用");
} public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean被調(diào)用");
} public void destroy() throws Exception {
System.out.println("DisposableBean被調(diào)用");
} //自定義的初始化函數(shù)
public void myInit() {
System.out.println("myInit被調(diào)用");
} //自定義的銷毀方法
public void myDestroy() {
System.out.println("myDestroy被調(diào)用");
} public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext被調(diào)用");
}
}</pre>
View Code
定義了后置處理器CusBeanPostProcessor 實現(xiàn)了BeanPostProcessor 接口。
[[圖片上傳失敗...(image-60f7f6-1535123798917)]](javascript:void(0); "復制代碼")
<pre>package com.demo.model; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class CusBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization被調(diào)用"); return bean;
} public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization被調(diào)用"); return bean;
}
}</pre>
[[圖片上傳失敗...(image-877b6a-1535123798917)]](javascript:void(0); "復制代碼")
在xml中配置bean和BeanPostProcessor。
<pre> <bean id="user" class="com.demo.model.UserBean" destroy-method="myDestroy" init-method="myInit">
<property name="name" value="abc"></property>
</bean>
<bean id="postProcessor" class="com.demo.model.CusBeanPostProcessor" /></pre>
測試:
<pre> ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
BeanFactory factory=context;
UserBean user=(UserBean)context.getBean("user");
((ClassPathXmlApplicationContext)context).close();</pre>
輸出結果:
UserBean類構造方法
set方法被調(diào)用
BeanNameAware被調(diào)用
BeanFactoryAware被調(diào)用
setApplicationContext被調(diào)用
postProcessBeforeInitialization被調(diào)用
InitializingBean被調(diào)用
myInit被調(diào)用
postProcessAfterInitialization被調(diào)用
DisposableBean被調(diào)用
myDestroy被調(diào)用
