通常彤守,應用程序開發(fā)人員不需要子類化ApplicationContext實現(xiàn)類醉途。相反毡熏,可以通過插入特殊集成接口的實現(xiàn)來擴展Spring IoC容器舍扰。下圖展示了Spring Bean的生命周期倦蚪。而在這其中,與一些拓展點是非常相關的边苹。也就是說陵且,這些拓展點作用了Bean的生命周期中。(在看下面的拓展點的時候个束,可以結合這個圖慕购,觀察拓展點所處于的生命周期位置)
1. FactoryBean(用于自定義實例化邏輯)
FactoryBean
通常是用來創(chuàng)建比較復雜的bean,一般的bean 直接用xml配置即可茬底,但如果一個bean的創(chuàng)建過程中涉及到很多其他的bean 和復雜的邏輯沪悲,用xml配置比較困難,這時可以考慮用FactoryBean阱表。
- 定義需要創(chuàng)建的Bean
public class Tool {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Tool(int id) {
this.id = id;
}
}
- 實現(xiàn)FactoryBean
public class ToolFactory implements FactoryBean<Tool> {
private int factoryId;
private int toolId;
//獲取所創(chuàng)建的Bean
@Override
public Tool getObject() throws Exception {
return new Tool(toolId);
}
//獲取對象類型
@Override
public Class<?> getObjectType() {
return Tool.class;
}
public int getFactoryId() {
return factoryId;
}
//設置是否單例
@Override
public boolean isSingleton() {
return false;
}
public void setFactoryId(int factoryId) {
this.factoryId = factoryId;
}
public int getToolId() {
return toolId;
}
public void setToolId(int toolId) {
this.toolId = toolId;
}
}
創(chuàng)建Tool
這個Bean的具體過程都交給了ToolFactory
來管理,也就是創(chuàng)建的細節(jié)都有它控制.
- 把
FactoryBean
創(chuàng)建Bean交給容器管理殿如。
@Configuration
public class FactoryBeanAppConfig implements InitializingBean,BeanPostProcessor {
//注入到容器里面
@Bean(name="tool")
public ToolFactory toolFactory() {
ToolFactory factory = new ToolFactory();
factory.setFactoryId(7070);
factory.setToolId(2);
return factory;
}
- 通過
name = "&tool"
來獲取到ToolFactory
,因為ToolFactory
本身也是Bean,由Spring容器管理.
//注入Tool
@Autowired
Tool tool;
//注入ToolFactory
@Resource(name = "&tool")
ToolFactory toolFactory;
2. InitializingBean和DisposableBean
IInitializingBean
和DisposableBean
中前者是在容器對Bean必要的屬性做了初始化后,再做后續(xù)的初始化最爬。后者是容器對Bean銷毀之前做一個回調(diào)涉馁。
- InitializingBean
InitializingBean
只有一個方法,允許你在初始化之后做個回調(diào)。
void afterPropertiesSet() throws Exception;
通常來說烂叔,不推薦使用InitializingBean
,因為它和Spring耦合太緊密了谨胞。推薦使用 @PostConstruct
注解 或者一個具體的 POJO 初始化方法固歪。推薦使用的與InitializingBean
效果是一樣的蒜鸡,但是前者就沒有和Spring耦合胯努。
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
而 @PostConstruct
注解 則需要在支持Servlet2.5的容器使用。
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
這三種方法的效果是一樣的逢防,但是當同時配置的時候叶沛,按照Spring Bean的生命周期,執(zhí)行的順序如下:
- 使用
@PostConstruct
注解的方法忘朝。 -
InitializingBean
中的afterPropertiesSet()
方法灰署。 - 自定義的
init()
方法。
對應的局嘁,銷毀中@PreDestroy
,DisposableBean
,自定義的destroy()
效果一樣溉箕,執(zhí)行順序與初始化的順序對應一樣。這兩類在初始化之前和銷毀之前的回調(diào)通常用于緩存的初始加載和緩存的清除這樣的場景悦昵。
3. BeanNameAware,BeanFactoryAware,ApplicationContextAware
-
BeanNameAware
使得對象能夠感知到bean的名稱肴茄。通常用于把beanName記錄在日志。 -
BeanFactoryAware
使得我們可以獲取到BeanFactory
,進而可以獲取到bean但指,或者判斷bean是否是單例寡痰。 -
ApplicationContextAware
使得我們獲取到ApplicationContext
的具體實現(xiàn)類這個容器。這個ApplicationContext
比BeanFactory
功能更強大棋凳。
使用 BeanNameAware
,BeanFactoryAware
,ApplicationContextAware
值需要實現(xiàn)接口里面相應的方法即可拦坠。通常來說,定義一個類變量來分別紀錄下感知的的Name,BeanFactory,ApplicationContext即可剩岳。
@Override
public void setBeanName(String s) {
System.out.println(s);
System.out.println("setBeanName方法被調(diào)用");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory.containsBean("person"));
System.out.println(beanFactory.isSingleton("person"));
System.out.println("setBeanFactory被調(diào)用,beanFactory");
}
//功能比beanFactory功能更強大些
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(applicationContext.getId());
System.out.println(applicationContext.containsBean("person"));
System.out.println("setApplicationContext被調(diào)用");
}
在大多數(shù)情況下贞滨,我們應該避免使用這些Aware
接口,因為它和Spring耦合太多拍棕。
4. BeanPostProcessor疲迂,BeanFactoryPostProcessor
-
BeanPostProcessor
是在整個bean已經(jīng)創(chuàng)建,并且設置好類成員屬性之后莫湘,即spring容器已經(jīng)實例化一個bean后尤蒿。通過回調(diào)方法去實現(xiàn)自定義的實例邏輯.通常用于檢查bean屬性的有效性,每個bean在初始化(init-method,InitializingBean等初始化方法)前后幅垮,都會回調(diào)BeanPostProcessor
中的方法腰池。 -
BeanFactoryPostProcessor
主要用于改變bean的Metadata。Spring容器允許BeanFactoryPostProcessor
去讀取配置元屬性忙芒,并改變它示弓。它在BeanPostProcessor
之前執(zhí)行。
public class MyBeanPostProcessor implements BeanPostProcessor,BeanFactoryPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if(bean instanceof Person) {
((Person) bean).setName("sb");
}
System.out.println("postProcessBeforeInitialization被調(diào)用");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization被調(diào)用");
return bean;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor被調(diào)用");
}
}
這樣呵萨,SpringBean的生命周期就被串聯(lián)起來了奏属。如下
首先容器啟動后,會對scope為singleton且非懶加載的bean進行實例化潮峦,
按照Bean定義信息配置信息囱皿,注入所有的屬性勇婴,
如果Bean實現(xiàn)了BeanNameAware接口,會回調(diào)該接口的setBeanName()方法嘱腥,傳入該Bean的id耕渴,此時該Bean就獲得了自己在配置文件中的id,
如果Bean實現(xiàn)了BeanFactoryAware接口,會回調(diào)該接口的setBeanFactory()方法齿兔,傳入該Bean的BeanFactory橱脸,這樣該Bean就獲得了自己所在的BeanFactory,
如果Bean實現(xiàn)了ApplicationContextAware接口,會回調(diào)該接口的setApplicationContext()方法分苇,傳入該Bean的ApplicationContext添诉,這樣該Bean就獲得了自己所在的ApplicationContext,
如果有Bean實現(xiàn)了BeanPostProcessor接口医寿,則會回調(diào)該接口的postProcessBeforeInitialzation()方法吻商,
如果Bean實現(xiàn)了InitializingBean接口,則會回調(diào)該接口的afterPropertiesSet()方法糟红,(初始化之一)
如果Bean配置了init-method方法艾帐,則會執(zhí)行init-method配置的方法,(初始化之一)
如果有Bean實現(xiàn)了BeanPostProcessor接口盆偿,則會回調(diào)該接口的postProcessAfterInitialization()方法柒爸,
經(jīng)過流程9之后,就可以正式使用該Bean了,對于scope為singleton的Bean,Spring的ioc容器中會緩存一份該bean的實例事扭,而對于scope為prototype的Bean,每次被調(diào)用都會new一個新的對象捎稚,期生命周期就交給調(diào)用方管理了,不再是Spring容器進行管理了
容器關閉后求橄,如果Bean實現(xiàn)了DisposableBean接口今野,則會回調(diào)該接口的destroy()方法,
如果Bean配置了destroy-method方法罐农,則會執(zhí)行destroy-method配置的方法条霜,至此,整個Bean的生命周期結束涵亏。
參考文章:
spring官方文檔
Spring Bean生命周期