閱讀552 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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工廠的完整體係,比較複雜,不過我們隻需要關注其中的幾個核心工廠。
  factory-inherit.png  
    (看不清楚,請下載圖片來看,比較清晰)
    這些工廠類沒有在同一個包內,分布在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方法),我們關注下最主要的這個方法:
public Object getBean(String name, Class requiredType, Object[] args) throws BeansException {
        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;
    }
    當你調用getBean獲取一個bean的時候,spring首先查找單例緩存中是否已經有這個bean,有的話直接返回(首先會判斷是否已經創建),如果沒有,spring就開始創建這個bean:首先獲取bean的定義(BeanDefinition),檢測bean是否定義在父工廠中,有的話調用父工廠的getBean方法;沒有就檢測bean是singleton還是prototype,如果是singleton就是創建bean並加入緩存以便下次直接調用,如果是prototype,就在每次調用時重新創建一個bean實例。注意createBean(beanName, mergedBeanDefinition, args); 這個方法,這是創建bean的核心方法,並且是一個abstract方法,將被子類實現。
    看看是如何獲取bean的定義的,
protected RootBeanDefinition getMergedBeanDefinition(String name, boolean includingAncestors)
        
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 BeanDefinition getBeanDefinition(String beanName) throws BeansException;

protected abstract Object createBean(
            String beanName, RootBeanDefinition mergedBeanDefinition, Object[] args) 
throws BeanCreationException;
 
    基本了解了AbstractBeanFactory 後,我們來看看它的子類的AbstractAutowireCapableBeanFactory ,這個類實現了createBean() ,在這個方法中我們將看到與上麵bean的生命周期圖對應的bean的創建過程,英文注釋已經非常清楚:
protected Object createBean(String beanName, RootBeanDefinition mergedBeanDefinition, Object[] args)
            
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;
    }
    通過instanceof操作符來判斷bean是否實現了用於生命周期回調的接口,然後調用相應的回調方法,可以看到spring充分實踐了針對接口編程的原則,雖然很誇張的一個方法一個接口的地步,不過這些接口也是作為mark interface用於標記回調。結合上麵的生命周期圖看這段代碼將很好理解。有了bean的創建方法,那麼如何獲取bean在配置文件中的定義信息呢?也就是在哪裏實現了 getBeanDefinition方法呢?答案就在AbstractAutowireCapableBeanFactory 的子類DefaultListableBeanFactory中。

    DefaultListableBeanFactory 不僅繼承了AbstractAutowireCapableBeanFactory ,還實現了BeanDefinitionRegistry和ConfigurableListableBeanFactory接口。其中ConfigurableListableBeanFactory接口是定義了分析和修改bean定義信息的回調方法,暫時不去管它。看看BeanDefinitionRegistry接口:
public interface 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的定義信息:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            
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);
    }
    beanDefinitionMap就是我們存儲工廠類中注冊的bean的信息,用bean name做為key:
/** Map of bean definition objects, keyed by bean name */
    
private final Map beanDefinitionMap = new HashMap();
 
    DefaultListableBeanFactory 重寫了
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
模板方法用於提供bean定義信息給getBean方法用於創建bean實例。getBeanDefinition的從beanDefinitionMap 查找bean定義即可:
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
        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 ,沒有定義新的方法,隻是有兩個重載的構造函數:
  
public class XmlBeanFactory extends 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工廠的:
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {

    dot.gifdot.gif
    
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());
                }
   dot.gif
}
工具類BeanDefinitionReaderUtils中的注冊方法:
    public static void registerBeanDefinition(
            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

  上一篇:go  websphere應用服務器性能調整建議,針對運行一段時間後當機
  下一篇:go  jQuery使用手冊(收藏)