1. 程式人生 > >Spring原始碼分析之IOC(七)

Spring原始碼分析之IOC(七)

前面分析了finishBeanFactoryInitialization();留一下了doGetBean()這個方法,由於這個方法是Spring IOC的例項化真正工作的方法,所以特地拿出來單獨來說。
doGetBean()方法太長,下面截圖按照順序剪下來的話不多說,翻原始碼
這裡寫圖片描述
首先第一行就是根據傳進來的name,來確定它的原始名稱或者說將name的別名給它解析成規範的名字(beanName):如果name 以”&”開頭,則去掉”&”

protected String transformedBeanName(String name) {
        return
canonicalName(BeanFactoryUtils.transformedBeanName(name)); } public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); String beanName = name; ////BeanFactory.FACTORY_BEAN_PREFIX ="&" while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } return
beanName; } public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while
(resolvedName != null); return canonicalName; }

再看getSingleton(beanName);首先從快取中根據beanName去取,如果取到,則載入這個bean。Spring用DefaultSingletonBeanRegistry快取本地來儲存建立過的bean instance。使用singletonObjects 來實現SingleTon Bean instance的快取

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

然後進入getObjectForBeanInstance();得到bean。其原始碼如下圖
這裡寫圖片描述
如果通過上面getSingleton得到的例項是factory bean,則去建立一個factory bean instance。通過之前的getMergedLocalBeanDefintion得到一個合併後的RootBeanDefinition。
繼續往下看原始碼
這裡寫圖片描述
如果存在該父工廠,並且該beanDefinition不存在。則下面 originalBeanName(name)就是把之前beanName去掉的“&”再給它加上,然後用父工廠去getBean();迴圈重複呼叫doGetBean步驟,然後形成了遞迴處理。(注:個人理解是參照了 JVM中class的載入雙親委託模式就是class先交給 父類的類載入器去載入,如果在父類中沒有找到該class ,則一級一級的向子類載入器傳遞來載入。有不同也有類似的點)。
否則則進入下面的步驟: 將當前beanName標記為已經建立或者正在建立。
這裡寫圖片描述
這兒又看到getMergedLocalBeanDefinition();這個方法了。還是得到一個合併後的RootBeanDefinition mbd
檢查 mbd 是否是抽象的,如果是報出異常。然後 開始處理Bean的依賴關係。
首先 mbd.getDependsOn();dependsOn表示與當前bean有依賴關係的,這段依賴關係是在bean的註冊 階段就是ObtainBeanFactory();方法裡面先行生成的;然後迴圈遍歷處理每個有依賴關係isDependent()。

這裡寫圖片描述
上面這個檢查依賴關係的方法中分為兩段第一段是檢查當前已快取的dependentBeanMap(Map between dependent bean names: bean name –> Set of dependent bean names)中是否有存在迴圈依賴。第二段則是如果當前beanName沒有存在迴圈依賴。則根據從dependentBeanMap得到的依賴Bean,檢查是否與當前被依賴的Bean有迴圈依賴關係。(從beanName得到所有的依賴關係,然後檢查每個依賴dep是否反向依賴beanName,因為要例項化beanName,先例項化它的依賴Bean dep。避免有迴圈依賴的關係)
eg:
    判斷a —>b是否有迴圈依賴。如果根據a得到的Set A如果有b,則表示a有    迴圈依賴b。如果前面不存在迴圈依賴,然後就繼續檢查Set A中的每個bean是否有迴圈依賴b。如果存在,則表示a與b 之前存在迴圈依賴。

如果當前beanName與dependsOn不存在迴圈依賴關係,接著把當前的依賴關係快取到dependentBeanMap中。然後先去getBean(dep)這個被依賴的dep。
當處理完所有的依賴Bean後, 就要例項化自己了。
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
上面的原始碼就是如果bean是singleton和prototype分別進行不同的處理去例項化()這個bean,然後對例項化的bean進行型別檢查。
所以接下來就詳細分析下createBean()這個方法。

    //---------------------------------------------------------------------
    // Implementation of relevant AbstractBeanFactory template methods
    //---------------------------------------------------------------------

    /**
     * Central method of this class: creates a bean instance,
     * populates the bean instance, applies post-processors, etc.
     * @see #doCreateBean
     */
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

上面程式碼中先做了根據class屬性或者className 屬性來解析Bean,然後對重寫方法的進行校驗和標記。如果有代理就直接返回代理 ,否則就進行常規的doCreateBean(),又看到doXXX了這種命名,進行實際的處理工作。個人覺得可以加到自己的命名規範中^_^;
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這個方法很長,分開來看。

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        mbd.resolvedTargetType = beanType;

factoryBeanInstanceCache這個集合呢是 快取未例項化尚未完成的bean。這裡先清除快取,然後根據RootBeanDefinition生成一個BeanWrapper(用來分析和操作 JavaBean的)。createBeanInstance這個方法的說明就是採用Factory(工廠方法),自動裝配,或者簡單的例項化策略來建立某個bean的例項。

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

前面註冊的postProcessors在這裡用到了,用於修改BeanDefintion的定義屬性。例如AutowiredAnnotationBeanPostProcessor用來修改autoWired的屬性。

// Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory() {
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

這裡檢查當前bean是否滿足提前曝光或者快取(eagerly cache)原則:是否有迴圈引用,是否支援迴圈引用(預設是支援),必須是單例。提前曝光的是為了避免在迴圈引用的時候引發死迴圈,或者因為初始化複雜bean的時候引發效能問題。

// Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

這裡是初始化上面建立的bean 。populateBean()完成屬性注入,接著就是initializeBean();bean配置中有一個使用者的init-method的方法。而initializeBean()這個方法就是進入init-method指定的方法來呼叫完成使用者設定的初始化方法(Spring中已經執行過內部的初始化方法,這是使用者層面的初始化)。

if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }
// Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;

這段則是註冊銷燬方法。然後返回已經完成例項化的Bean。

===================================
這樣Spring IOC的過程基本就走了一遍了。作為新手的我又有了一些深的認識