接着上一篇說,我們再看下refresh方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 這邊我們裝載了bean放到了map中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 添加一些 Spring 本身需要的一些工具類
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();
// 上面部分是BeanPostProcessor的處理,相當於監聽器,可以對用戶的一些自定義功能進行處理。屬於bean擴展功能,有點aop的思想。
// Instantiate all remaining (non-lazy-init) singletons.
// 這邊對沒有延遲加載的bean進行實例化。
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;
}
}
}
下面主要看看實例化bean的這個方法finishBeanFactoryInitialization(beanFactory):
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isInfoEnabled()) {
this.logger.info("Pre-instantiating singletons in " + this);
}
synchronized (this.beanDefinitionMap) {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
}
上面有個isFactoryBean()方法,判斷這個bean是否是屬於FactoryBean類型。我們spring中管理了兩種bean:普通的bean和工廠Bean(即實現了FactoryBean接口的bean),當一個受Spring容器管理的bean 如果實現了FactoryBean接口 在bean實例化(getBean)階段 Spring會調用該bean的getObejct方法,返回的不一定是自身的實例,若想獲得自身bean可以通過加個&符號的方式來獲得,如:context.getBean("&sayHelloFactoryBean");
bean實例化時序圖:
最終將bean實例化後的bean實例對象以Map的形式保存在DefaultSingletonBeanRegistry類中的singletonObjects對象中,以beanName爲key,實例化對象爲value。
bean對象依賴關係時序圖:
Ioc 容器的擴展點
現在還有一個問題就是如何讓這些 Bean 對象有一定的擴展性,就是可以加入用戶的一些操作。那麼有哪些擴展點呢? Spring 又是如何調用到這些擴展點的?
對 Spring 的 Ioc 容器來說,主要有這麼幾個。BeanFactoryPostProcessor, BeanPostProcessor。他們分別是在構建 BeanFactory 和構建 Bean 對象時調用。還有就是 InitializingBean 和 DisposableBean 他們分別是在 Bean 實例創建和銷燬時被調用。用戶可以實現這些接口中定義的方法,Spring 就會在適當的時候調用他們。還有一個是 FactoryBean 他是個特殊的 Bean,這個 Bean 可以被用戶更多的控制。
這些擴展點通常也是我們使用 Spring 來完成我們特定任務的地方,如何精通 Spring 就看你有沒有掌握好 Spring 有哪些擴展點,並且如何使用他們,要知道如何使用他們就必須瞭解他們內在的機理。可以用下面一個比喻來解釋。
我們把 Ioc 容器比作一個箱子,這個箱子裏有若干個球的模子,可以用這些模子來造很多種不同的球,還有一個造這些球模的機器,這個機器可以產生球模。那麼他們的對應關係就是 BeanFactory 就是那個造球模的機器,球模就是 Bean,而球模造出來的球就是 Bean 的實例。那前面所說的幾個擴展點又在什麼地方呢? BeanFactoryPostProcessor 對應到當造球模被造出來時,你將有機會可以對其做出設當的修正,也就是他可以幫你修改球模。而 InitializingBean 和 DisposableBean 是在球模造球的開始和結束階段,你可以完成一些預備和掃尾工作。BeanPostProcessor 就可以讓你對球模造出來的球做出適當的修正。最後還有一個 FactoryBean,它可是一個神奇的球模。這個球模不是預先就定型了,而是由你來給他確定它的形狀,既然你可以確定這個球模型的形狀,當然他造出來的球肯定就是你想要的球了,這樣在這個箱子里尼可以發現所有你想要的球
Ioc 容器如何爲我所用
前面的介紹了 Spring 容器的構建過程,那 Spring 能爲我們做什麼,Spring 的 Ioc 容器又能做什麼呢?我們使用 Spring 必須要首先構建 Ioc 容器,沒有它 Spring 無法工作,ApplicatonContext.xml 就是 Ioc 容器的默認配置文件,Spring 的所有特性功能都是基於這個 Ioc 容器工作的,比如後面要介紹的 AOP。
Ioc 它實際上就是爲你構建了一個魔方,Spring 爲你搭好了骨骼架構,這個魔方到底能變出什麼好的東西出來,這必須要有你的參與。那我們怎麼參與?這就是前面說的要了解 Spring 中那有些擴展點,我們通過實現那些擴展點來改變 Spring 的通用行爲。至於如何實現擴展點來得到我們想要的個性結果,Spring 中有很多例子,其中 AOP 的實現就是 Spring 本身實現了其擴展點來達到了它想要的特性功能,可以拿來參考。
參考:http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/#major2