前言
前面幾篇關于Spring的文章簡單闡述了使用BeanFactory作為容器時bean的初始化過程。然而在實際使用中,我們并不會直接接觸和編碼BeanFactory,我們通常會使用另外一個功能更強、更完善的容器ApplicationContext。本文粗略講述了ApplicationContext對于BeanFactory的功能擴展,并將重點放在了Spring在容器啟動和初始化過程中提供的擴展點和事件發布上。擴展點讓我們能夠“插手和干預”Bean的初始化,通過容器發布的事件得以了解容器的一些內部過程。
ApplicationContext的功能擴展
ApplicationContext是“事實上”的容器標準,它基于BeanFactory并對其做了一些功能上的擴展。例如:
- 通過MessageResource支持國際化
- 提供了容器內部的消息發布機制
- 自動添加BeanFactoryPostProcessor、BeanPostProcessor到容器中
等。
由于ApplicationContext對于BeanFactory的擴展不是本文闡述的重點,所以略過。
Spring容器初始化中的擴展點
Spring容器初始化中的擴展點不僅包括了Beanfactory提供的也包含了ApplictionContext增強的。
從前面幾篇關于容器初始化的文章可以得出,從xml到實例化并初始化完bean大體上經歷了兩個過程:
- 容器啟動過程:這個過程包括了讀取xml文件,并替換一些系統或者自定義變量,將xml標簽解析成BeanDefinitionwrapper。
- 容器初始化過程:這個過程包括了解析BeanDefinition中包含的Bean信息,完成Bean的實例化(Instantiation)和初始化(Initialization)過程。
而ApplicationContext將容器啟動和初始化過程細化成了一些模板函數,構成以下步驟。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
整個過程及其中的擴展點可以表示成下圖:
圖中表示出了Spring容器中設計到的很多擴展點,主要可以分為以下幾類:
- BeanFactoryPostProcessor
- 各種Aware
- BeanPostProcessor
- 隱藏的一些特殊功能
下文將一項一項地進行梳理
BeanFactoryPostProcessor
簡介
BeanFactoryPostProcessor是一個很重要的接口,其中只有一個方法
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
它起作用的時機發生在解析成BeanDefinition后,實例化之前。從名字可以看出來,BeanFactoryPostProcessor針對的應該是容器級別的擴展,名為“BeanFactory PostProcessor”即對容器中所有的BeanDefinition都起普遍作用。BeanFactoryPostProcessor有幾個我們比較常用的子類PropertyPlaceholderConfigurer、CustomEditorConfigurer,前者用于配置文件中的${var}變量替換,后者用于自定義編輯BeanDefinition中的屬性值,合理利用CustomEditorConfigurer會有一些意想不到的效果(例如可以通過修改某些屬性實現類似aop的功能)。
使用
如果是在BeanFactory中使用,我們需要
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
configurer.setLaction("xxx");
configurer.postProcessBeanFactory(beanFactory);
很繁瑣,很麻煩,而且通常我們并不喜歡硬編碼直接使用BeanFactory。在ApplicationContext中得到了改善,使用BeanFactoryPostProcessor只需要在xml文件中進行相應的配置就行,因為ApplicationContext在初始化過程中會調用invokeBeanFactoryPostProcessors(beanFactory),該函數會找出所有BeanFactoryPostProcessor類型的bean,調用postProcessBeanFactory方法。
BeanPostProcessor
簡介
BeanPostProcessor很容易和BeanFactoryPostProcessor混淆,但從名字上來說,BeanPostProcessor是“Bean PostProcessor”,主要針對于Bean這一級別,關注的主要是Bean實例化后,初始化前后的。為什么說主要呢?因為存在特例,有一個BeanPostProcessor的調用并不是發生在實例化后,初始化前后。BeanPostProcessor接口存在兩個方法,從名字可以看粗一個調用在初始化之前,一個調用在初始化之后。
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
BeanPostProcessor在BeanFactory的初始化bean的函數initializeBean中,主要代碼為,基本就是取出所有的BeanPostProcessor,然后遍歷調用其postProcessBeforeInitialization或者postProcessAfterInitialization方法。
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
使用
Spring利用BeanPostProcessor給了我們在bean初始化前后“doSomething”的機會。
在BeanFactory中使用需要編碼
beanFactory.addBeanPostProcessor(new SomeBeanPostProcessor);
但是在ApplicationContext中,我們只需要將自定義的BeanPostProcessor配置到xml文件中即可。ApplicationContext在初始化過程中會識別所有的BeanPostProcessors并添加到BeanFactory中。
各種Aware
簡介
這種類型的擴展點是我們比較熟悉的了,例如ApplicationContextAware、BeanFactoryAware等,Aware的接口用于標識“我需要這個對象”,例如ApplicationContextAware通知容器我需要“當前的ApplicationContext對象”。這個Spring給我們提供的一種用于獲取有用對象的一種好的方式。
使用
需要注意的是,Aware起作用的時機是在Bean已經完成實例化之后,初始化Bean的同時。而且需要注意的是BeanFactory對于Aware的處理和ApplicationContext是不同的。
先看BeanFactory中的處理方式,各種Aware被調用的地方是在初始化bean的函數
initializeBean中
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
可以看到其發生在invokeInitMethods之前。而ApplicationContext怎么處理呢?ApplicationContext本身是利用BeanFactory進行容器的初始化,而BeanFactory卻硬編碼了invokeAwareMethods中Aware的類型,那ApplicationContext究竟是怎么調用ApplicationContextAware的呢,答案就在函數prepareBeanFactory中,
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
ApplicationContext為beanFactory增加了ApplicationContextAwareProcessor,ApplicationContextAwareProcessor是一種BeanPostProcessor。前文提到BeanPostProcessor發生在bean初始化前后,在bean初始化之前將調用postProcessBeforeInitialization方法,ApplicationContextAwareProcessor#postProcessBeforeInitialization如下:
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
可以看出ApplicationContext利用ApplicationContextAwareProcessor完成了ApplicationContext中特有的一些Aware的調用,發生的時機在初bean始化之前。
一種特殊的BeanPostProcessor-InstantiationAwareBeanPostProcessor
前文提到BeanPostProcessor主要作用于Bean實例化后,初始化前后,但是存在特例,InstantiationAwareBeanPostProcessor就是特例,其發生在Bean實例化前,
在真正調用doCreate()創建bean實例化之前,調用了resolveBeforeInstantiation進行了短路操作,如果此方法返回值不為空則直接返回bean。spring注釋“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. ”給BeanPostProcessors一個機會返回代理proxy對象。
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
我們熟知的AOP,對target對象進行代理就是實現了InstantiationAwareBeanPostProcessor接口,在Bean實例化之前短路操作返回代理Proxy對象。
ApplicationContext的事件發布
--待續
總結
本文總結了Spring容器中幾種使用較多的擴展機制,Spring作為一個設計良好的框架,遵循了“對修改封閉,對擴展開放”的原則,我們可以根據自己的實際需要來自定義BeanFactoryPostProcessor,BeanPostProcessor來在bean的生命周期里doSomething,實現各種Aware接口拿到容器中提供的一些有用對象,通過自定義監聽器監聽容器的事件等。