Spring之Bean的作用域與生命周期
在前面博客中提到容器啟動獲得BeanDefinition對象中有一個scope 屬性。該屬性控制著bean對象的作用域。本章節介紹Bean的作用域及生命周期,了解bean是怎麽來的又怎麽沒的。
一、Bean的作用域
在Bean容器啟動會讀取bean的xml配置文件,然後將xml中每個bean元素分別轉換成BeanDefinition對象。在BeanDefinition對象中有scope 屬性,就是它控制著bean的作用域。
Spring框架支持5種作用域,有三種作用域是當開發者使用基於web的ApplicationContext的時候才生效的。下面就是Spring直接支持的作用域了,當然開發者也可以自己定制作用域。
作用域 |
描述 |
單例(singleton) |
(默認)每一個Spring IoC容器都擁有唯一的一個實例對象 |
原型(prototype) |
一個Bean定義,任意多個對象 |
請求(request) |
一個HTTP請求會產生一個Bean對象,也就是說,每一個HTTP請求都有自己的Bean實例。只在基於web的Spring ApplicationContext中可用 |
會話(session) |
限定一個Bean的作用域為HTTPsession的生命周期。同樣,只有基於web |
全局會話(global session) |
限定一個Bean的作用域為全局HTTPSession的生命周期。通常用於門戶網站場景,同樣,只有基於web的Spring ApplicationContext可用 |
我們可以以XMLInstance類為基礎演示一下singleton和prototype作用域。
這裏使用通過BeanFactory的getBean方法獲取兩次bean對象。
XMLInstance instance=(XMLInstance)factory.getBean("xmlinstance"); instance.setName("123"); instance.Breath(); instance=(XMLInstance)factory.getBean("xmlinstance"); instance.Breath();
如果我們采用bean默認的作用域singleton,如下配置,則兩個getbean獲取的對象是一致的。
<bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="singleton">
<property name="air" ref="CleanAir"></property>
<property name="name" value="abc"></property>
</bean>
輸出結果: Name:123;Air:CleanAir Name:123;Air:CleanAir
如果我們采用bean默認的作用域singleton,如下配置,則兩個getbean獲取的對象是不一致的。
<bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="prototype">
<property name="air" ref="CleanAir"></property>
<property name="name" value="abc"></property>
</bean>
輸出結果: Name:123;Air:CleanAir Name:abc;Air:CleanAir
二、Bean的生命周期
前面章節介紹了bean容器以及bean的配置與註入,本章節學習bean的生命周期,了解bean是怎麽來的又是怎麽沒的。
1.首先容器啟動後,會對scope為singleton且非懶加載的bean進行實例化,
2.按照Bean定義信息配置信息,註入所有的屬性,
3.如果Bean實現了BeanNameAware接口,會回調該接口的setBeanName()方法,傳入該Bean的id,此時該Bean就獲得了自己在配置文件中的id,
4.如果Bean實現了BeanFactoryAware接口,會回調該接口的setBeanFactory()方法,傳入該Bean的BeanFactory,這樣該Bean就獲得了自己所在的BeanFactory,
5.如果Bean實現了ApplicationContextAware接口,會回調該接口的setApplicationContext()方法,傳入該Bean的ApplicationContext,這樣該Bean就獲得了自己所在的ApplicationContext,
6.如果有Bean實現了BeanPostProcessor接口,則會回調該接口的postProcessBeforeInitialzation()方法,
7.如果Bean實現了InitializingBean接口,則會回調該接口的afterPropertiesSet()方法,
8.如果Bean配置了init-method方法,則會執行init-method配置的方法,
9.如果有Bean實現了BeanPostProcessor接口,則會回調該接口的postProcessAfterInitialization()方法,
10.經過流程9之後,就可以正式使用該Bean了,對於scope為singleton的Bean,Spring的ioc容器中會緩存一份該bean的實例,而對於scope為prototype的Bean,每次被調用都會new一個新的對象,期生命周期就交給調用方管理了,不再是Spring容器進行管理了
11.容器關閉後,如果Bean實現了DisposableBean接口,則會回調該接口的destroy()方法,
12.如果Bean配置了destroy-method方法,則會執行destroy-method配置的方法,至此,整個Bean的生命周期結束。 這裏在UserBean類基礎上進行改造,增加了name屬性並實現了ApplicationContextAware接口。
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方法被調用"); } public UserBean() { System.out.println("UserBean類構造方法"); } public void setBeanName(String name) { System.out.println("BeanNameAware被調用"); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryAware被調用"); } public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean被調用"); } public void destroy() throws Exception { System.out.println("DisposableBean被調用"); } //自定義的初始化函數 public void myInit() { System.out.println("myInit被調用"); } //自定義的銷毀方法 public void myDestroy() { System.out.println("myDestroy被調用"); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("setApplicationContext被調用"); } }View Code
定義了後置處理器CusBeanPostProcessor 實現了BeanPostProcessor 接口。
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被調用"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization被調用"); return bean; } }
在xml中配置bean和BeanPostProcessor。
<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" />
測試:
ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"}); BeanFactory factory=context; UserBean user=(UserBean)context.getBean("user"); ((ClassPathXmlApplicationContext)context).close();
輸出結果:
UserBean類構造方法
set方法被調用
BeanNameAware被調用
BeanFactoryAware被調用
setApplicationContext被調用
postProcessBeforeInitialization被調用
InitializingBean被調用
myInit被調用
postProcessAfterInitialization被調用
DisposableBean被調用
myDestroy被調用
Spring之Bean的作用域與生命周期