spring IOC容器實現探討
spring IOC容器的實現,一開始我被複雜的接口和類所掩埋,看不清整體的思路和設計,踟躕於代碼叢林中,摸不清前進的方向。一開始我就決定隻研讀以xml文件做配置文件的XmlFactoryBean的具體實現為主要目標,漸漸地有了點感覺,用UML把spring中的bean工廠體係展現出來之後就更清晰了,讓你不得不感歎設計的精巧和複雜。本文隻是我個人對spring IOC實現的理解,如有錯誤,請不吝賜教,謝謝。首先,需要理解的是spring容器中bean的生命周期,《spring in action》中的那張圖是最好的解釋,結合這張圖和源碼來解讀spring中IOC的實現將非常容易理解。這張圖完整展示了spring容器中一個bean從創建到銷毀的整個生命周期。

1. 容器尋找Bean的定義信息並且將其實例化。
2.受用依賴注入,Spring按照Bean定義信息配置Bean的所有屬性。
3.如果Bean實現了BeanNameAware接口,工廠調用Bean的setBeanName()方法傳遞Bean的ID。
4.如果Bean實現了BeanFactoryAware接口,工廠調用setBeanFactory()方法傳入工廠自身。
5.如果BeanPostProcessor和Bean關聯,那麼它們的postProcessBeforeInitialzation()方法將被調用。
6.如果Bean指定了init-method方法,它將被調用。
7.最後,如果有BeanPsotProcessor和Bean關聯,那麼它們的postProcessAfterInitialization()方法將被調用。
到這個時候,Bean已經可以被應用係統使用了,並且將被保留在Bean Factory中知道它不再需要。有兩種方法可以把它從Bean Factory中刪除掉。
1.如果Bean實現了DisposableBean接口,destory()方法被調用。
2.如果指定了訂製的銷毀方法,就調用這個方法。
下麵我們將會看到,這些bean創建銷毀的每個階段是如何在源碼中實現的。
再看看spring中bean工廠的完整體係,比較複雜,不過我們隻需要關注其中的幾個核心工廠。

(看不清楚,請下載圖片來看,比較清晰)
這些工廠類沒有在同一個包內,分布在org.springframework.beans以及它的子包內,把它們放在一起就看的比較清楚了。我們需要關注的是這麼兩個類:org.springframework.beans.factory.support.AbstractBeanFactory
org.springframework.beans.factory.support.DefaultListableBeanFactory
以及接口:
org.springframework.beans.factory.support.BeanDefinitionRegistry
AbstractBeanFactory作為BeanFactory接口的抽象實現類,是其他工廠類的父類,提供了bean的singlton緩存、singleton/prototype的決定、bean的別名以及bean和它的子類bean的定義合並(bean definition merging for child bean definitions)和銷毀。這裏有3個重載的getBean方法(實現BeanFactory定義的getBean方法),我們關注下最主要的這個方法:
String beanName = transformedBeanName(name);
Object bean = null;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = null;
//從單例緩存中獲取
synchronized (this.singletonCache) {
sharedInstance = this.singletonCache.get(beanName);
}
if (sharedInstance != null) {
if (isSingletonCurrentlyInCreation(beanName)) {
if (logger.isDebugEnabled()) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForSharedInstance(name, sharedInstance);
}
else {
// Fail if we're already creating this singleton instance:
// We're assumably within a circular reference.
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//檢測bean是否定義在父工廠
if (getParentBeanFactory() != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
if (getParentBeanFactory() instanceof AbstractBeanFactory) {
// Delegation to parent with args only possible for AbstractBeanFactory.
return ((AbstractBeanFactory) getParentBeanFactory()).getBean(name, requiredType, args);
}
else if (args == null) {
// No args -> delegate to standard getBean method.
return getParentBeanFactory().getBean(name, requiredType);
}
else {
throw new NoSuchBeanDefinitionException(beanName,
"Cannot delegate to parent BeanFactory because it does not supported passed-in arguments");
}
}
//獲取BeanDefinition
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
checkMergedBeanDefinition(mergedBeanDefinition, beanName, requiredType, args);
// Create bean instance.
//創建bean,如果為為singleton
if (mergedBeanDefinition.isSingleton()) {
synchronized (this.singletonCache) {
// Re-check singleton cache within synchronized block.
sharedInstance = this.singletonCache.get(beanName);
if (sharedInstance == null) {
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
this.currentlyInCreation.add(beanName);
try {
sharedInstance = createBean(beanName, mergedBeanDefinition, args);
//加進單例緩存
addSingleton(beanName, sharedInstance);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroyDisposableBean(beanName);
throw ex;
}
finally {
this.currentlyInCreation.remove(beanName);
}
}
}
bean = getObjectForSharedInstance(name, sharedInstance);
}
//如果是prototype
else {
// It's a prototype -> create a new instance.
bean = createBean(beanName, mergedBeanDefinition, args);
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return bean;
}
看看是如何獲取bean的定義的,
throws BeansException {
String beanName = transformedBeanName(name);
// Efficiently check whether bean definition exists in this factory.
if (includingAncestors && !containsBeanDefinition(beanName) &&
getParentBeanFactory() instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName, true);
}
// Resolve merged bean definition locally.
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
調用重載的getMergedBeanDefinition合並父工廠和子工廠中的bean定義,注意getBeanDefinition(beanName),這是一個抽象方法,延遲到子類實現以便提供獲取bean定義的具體方法,這個方法和 createBean 一樣都是template method模式的應用。看看它們的定義:
protected abstract Object createBean(
String beanName, RootBeanDefinition mergedBeanDefinition, Object[] args) throws BeanCreationException;
基本了解了AbstractBeanFactory 後,我們來看看它的子類的AbstractAutowireCapableBeanFactory ,這個類實現了createBean() ,在這個方法中我們將看到與上麵bean的生命周期圖對應的bean的創建過程,英文注釋已經非常清楚:
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName +
"' with merged definition [" + mergedBeanDefinition + "]");
}
Object bean = null;
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
if (mergedBeanDefinition.hasBeanClass()) {
bean = applyBeanPostProcessorsBeforeInstantiation(mergedBeanDefinition.getBeanClass(), beanName);
if (bean != null) {
return bean;
}
}
// Guarantee initialization of beans that the current one depends on.
if (mergedBeanDefinition.getDependsOn() != null) {
for (int i = 0; i < mergedBeanDefinition.getDependsOn().length; i++) {
getBean(mergedBeanDefinition.getDependsOn()[i]);
}
}
BeanWrapper instanceWrapper = null;
Object originalBean = null;
String errorMessage = null;
try {
// Instantiate the bean.
errorMessage = "Instantiation of bean failed";
if (mergedBeanDefinition.getFactoryMethodName() != null) {
instanceWrapper = instantiateUsingFactoryMethod(beanName, mergedBeanDefinition, args);
}
else if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mergedBeanDefinition.hasConstructorArgumentValues() ) {
instanceWrapper = autowireConstructor(beanName, mergedBeanDefinition);
}
else {
// No special handling: simply use no-arg constructor.
instanceWrapper = instantiateBean(beanName, mergedBeanDefinition);
}
bean = instanceWrapper.getWrappedInstance();
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
if (isAllowCircularReferences() && isSingletonCurrentlyInCreation(beanName)) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean with name '" + beanName +
"' to allow for resolving potential circular references");
}
addSingleton(beanName, bean);
}
// Initialize the bean instance.
errorMessage = "Initialization of bean failed";
populateBean(beanName, mergedBeanDefinition, instanceWrapper);
if (bean instanceof BeanNameAware) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking setBeanName on BeanNameAware bean '" + beanName + "'");
}
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanFactoryAware) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking setBeanFactory on BeanFactoryAware bean '" + beanName + "'");
}
((BeanFactoryAware) bean).setBeanFactory(this);
}
originalBean = bean;
bean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
invokeInitMethods(beanName, bean, mergedBeanDefinition);
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mergedBeanDefinition.getResourceDescription(), beanName, errorMessage, ex);
}
// Register bean as disposable, and also as dependent on specified "dependsOn" beans.
registerDisposableBeanIfNecessary(beanName, originalBean, mergedBeanDefinition);
return bean;
}
DefaultListableBeanFactory 不僅繼承了AbstractAutowireCapableBeanFactory ,還實現了BeanDefinitionRegistry和ConfigurableListableBeanFactory接口。其中ConfigurableListableBeanFactory接口是定義了分析和修改bean定義信息的回調方法,暫時不去管它。看看BeanDefinitionRegistry接口:
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
String[] getAliases(String beanName) throws NoSuchBeanDefinitionException;
void registerAlias(String beanName, String alias) throws BeansException;
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeansException;
......
}
一係列用於獲取bean定義信息的方法,這個接口我們將在後麵的代碼中看到,作為一個mark inteface。注意咯,這個接口中非常關鍵的一個方法就是registerBeanDefinition,這個方法用於向bean工廠注冊解析的每個bean定義,我們將在xml文件的解析的環節看到調用這個方法注冊bean定義信息。
DefaultListableBeanFactory實現了BeanDefinitionRegistry 接口,可以看到它實現了關鍵的registerBeanDefinition用於將bean的定義注冊到工廠類中,其中維護了一個Map用於存儲bean的定義信息:
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "Bean definition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': there's already [" + oldBeanDefinition + "] bound");
}
else {
if (logger.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
}
this.beanDefinitionMap.put(beanName, beanDefinition);
// Remove corresponding bean from singleton cache, if any.
// Shouldn't usually be necessary, rather just meant for overriding
// a context's default beans (e.g. the default StaticMessageSource
// in a StaticApplicationContext).
removeSingleton(beanName);
}
private final Map beanDefinitionMap = new HashMap();
DefaultListableBeanFactory 重寫了
BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (logger.isDebugEnabled()) {
logger.debug("No bean named '" + beanName + "' found in " + toString());
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
看到了這裏是不是覺的有點煳塗,我還是建議有興趣地找來spring1.2的源碼來看看就很清晰了,充分利用eclipse的F3跳轉結合上麵的那張UML圖。
OK,有了注冊bean定義信息的方法(registerBeanDefinition),有了獲取bean定義信息的方法(getBeanDefinition ),有了創建bean的方法(createBean),那麼在哪裏調用這些方法呢?createBean我們已經知道是在BeanFactory的getBean方法時調用,getBeanDefinition 又是在creatBean時調用用於獲取bean的定義信息,那麼注冊bean定義信息的方法肯定是在xml文件解析階段被調用。
XmlBeanFactory繼承DefaultListableBeanFactory ,沒有定義新的方法,隻是有兩個重載的構造函數:
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
初始化XmlBeanFactory時調用XmlBeanDefinitionReader讀取xml配置文件,而XmlBeanDefinitionReader的loadBeanDefinitions方法,載入xml文件並且調用XmlBeanDefinitionParser 解析xml文件同時注冊bean定義信息到bean工廠,這幾個類的協作以及它們繼承體係也非常清晰,在此不再詳述(累啊),XmlBeanDefinitionParser是一個接口,具體的實現類是org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser,我們關注的就是它是怎麼注冊bean信息到bean工廠的:


if (IMPORT_ELEMENT.equals(node.getNodeName())) {
importBeanDefinitionResource(ele);
}
else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
String name = ele.getAttribute(NAME_ATTRIBUTE);
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);
}
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);
//關鍵代碼,調用工具類將bean定義注冊到beanFactory
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
}

}
BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {
// Register bean definition under primary name.,注冊bean
beanFactory.registerBeanDefinition(bdHolder.getBeanName(), bdHolder.getBeanDefinition());
// Register aliases for bean name, if any.,注冊別名
if (bdHolder.getAliases() != null) {
for (int i = 0; i < bdHolder.getAliases().length; i++) {
beanFactory.registerAlias(bdHolder.getBeanName(), bdHolder.getAliases()[i]);
}
}
}
注意這裏的beanFactory是BeanDefinitionRegistry類型 ,DefaultListableBeanFactory實現了這個接口。
更多內容,比如spring是怎麼把bean的屬性注入的?答案在BeanWrapperImpl中的一係列setPropertyXXX方法。BeanFactory是如何實例化bean的呢?具體展開請看org.springframework.beans.factory.support.InstantiationStrategy 接口,一個典型的策略模式的應用,兩個實現類:SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy。我們知道spring有3種注入方式:setter、構造函數以及Method Inject。這裏的CglibSubclassingInstantiationStrategy使用cglib庫用於實現method inject。這樣一篇小文容不下這麼多內容,還是有興趣的自己找源碼讀讀。
寫到這裏,我對自己的文字表達能力產生懷疑,我能不能把這些所有的信息都說清楚呢?感覺很不滿意,將就吧,也算是自己的學習總結。
讀spring源碼這段時間,最深的幾點體會:
1)單元測試非常重要,充分感受到了單元測試作為項目文檔的優勢。看不懂一個類,找到這個類的測試類就OK!
2)針對接口編程的原則,spring處處體現了這個原則,繁多的接口帶來的是鬆耦合、高內聚並且易於擴展的架構,但也帶來了一定的理解難度。作為通用型框架也許需要這麼考慮,在實際項目中的取舍還是要自己把握。
3)設計模式的使用,spring中應用了很多模式,比如template method,比如strategy和factory method、visitor、singleton等,簡直是一本模式實踐的良好教材。
文章轉自莊周夢蝶 ,原文發布時間5.17
最後更新:2017-05-17 13:35:42
上一篇:
websphere應用服務器性能調整建議,針對運行一段時間後當機
下一篇:
jQuery使用手冊(收藏)
在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”
《數據分析實戰:基於EXCEL和SPSS係列工具的實踐》一3.3 耗時耗力的數據整理過程
大數據獨角獸Palantir之核心技術探秘
JS中window.open和window.opener的使用
阿裏雲全球首批MVP — 傅奎專訪
ADAM助力傳統數據庫應用上雲
Users’ Choice: Application Server Rankings-09/2008
來到阿裏雲後,SRS大神楊成立說:“終於可以不用裝大神了”
PostgreSQL 按需切片的實現(TimescaleDB插件自動切片功能的plpgsql schemaless實現)
科普丨【計算機視覺】OpenCV中直方圖處理函數簡述