Spring IOC 源碼學習4 getBean

1 容器的初始化

1.1 SpringIoc 容器的工做流以下圖所示

1.2 實現流程

1.2.1 容器初始化

  • 經過Resource ResourceLoader 加載 Configuration Metadata
  • 解析 Configuration Metadata信息,封裝成 BeanDefinition 並註冊到 BeanDefinitionRegistry 中

1.2.2 加載bean

  • 經過BeanFactory.getBean() 加載bean
  • 對bean信息進行初始化

2 源碼解析

2.1 源碼警告

  • 當顯示或者隱式地調用 BeanFactory.getBean(String name) 方法時,則會觸發加載 Bean 階段。代碼以下:

2.1.1 getBean

// 方法位於AbstractBeanFactory.java
public Object getBean(String name) throws BeansException {
    // getBean 是一個空殼方法,全部的邏輯都封裝在 doGetBean 方法中
    return doGetBean(name, null, null, false);
}
複製代碼

2.1.2 doGetBean

  • 內部其實調用的doGetBean(Spring 套路都是這樣子哈哈,包括事物那裏)
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {

    /*
     * 經過 name 獲取 beanName。這裏不使用 name 直接做爲 beanName 有兩點緣由:
     * 1. 若是 name 是 alias ,則獲取對應映射的 beanName 。
     * 2. 剝離工廠引用前綴&
     */
    final String beanName = transformedBeanName(name);
    Object bean;

    /*
     * 從緩存中或者實例工廠中獲取 Bean 對象
     * 從緩存中獲取單例 bean。Spring 是使用 Map 做爲 beanName 和 bean 實例的緩存的,因此這
     * 裏暫時能夠把 getSingleton(beanName) 等價於 beanMap.get(beanName)。固然,實際的
     * 邏輯並不是如此簡單,後面再細說。
     */
    Object sharedInstance = getSingleton(beanName);

    /*
     * 若是 sharedInstance = null代表這個實例還沒建立。
     * BeanFactory 只會在調用 getBean 獲取 bean 時再實例化,也就是懶加載。
     * BeanFactory 不會屢次實例化單例 bean。
     */
    if (sharedInstance != null && args == null) {
        //記錄日誌 沒啥可說的
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
      
        /*
         * 完成 FactoryBean 的相關處理,並用來獲取 FactoryBean 的處理結果
         * 若是 sharedInstance 是普通的單例 bean,下面的方法會直接返回。但若是 
         * sharedInstance 是 FactoryBean 類型的,則需調用 getObject 工廠方法獲取真正的bean 實例。
         */
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    /*
     *  sharedInstance 爲空,此時 beanName 對應的 bean 實例可能還未建立。也有可能父容器裏已經實例化,須要先去父容器查找 這裏有些不明白,先標註下而後後續查看
     */
    else {
        // BeanFactory 不緩存 Prototype 類型的 bean ,Spring 只解決單例模式下得循環依賴,在原型模式下若是存在循環依賴則會拋出異常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // 若是 sharedInstance = null,則到父容器中查找 bean 實例  getParentBeanFactory 後續在研究
        BeanFactory parentBeanFactory = getParentBeanFactory();
        //containsBeanDefinition 方法實際就是判斷 org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionMap 是否有key beanName
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 獲取 name 對應的 beanName,若是 name 是以 & 字符開頭,則返回 & + beanName
            String nameToLookup = originalBeanName(name);
            // 根據 args 是否爲空,以決定調用父容器哪一個方法獲取 bean
            if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            } 
            else {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // 合併父 BeanDefinition 與子 BeanDefinition,後面會單獨分析這個方法
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 檢查是否有 dependsOn 依賴,若是有則先初始化所依賴的 bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    /*
                     * 檢測是否存在 depends-on 循環依賴,若存在則拋異常。好比 A 依賴 B,
                     * B 又依賴 A,他們的配置以下:
                     *   <bean id="beanA" class="BeanA" depends-on="beanB">
                     *   <bean id="beanB" class="BeanB" depends-on="beanA">
                     *   
                     * beanA 要求 beanB 在其以前被建立,但 beanB 又要求 beanA 先於它
                     * 建立。這個時候造成了循環,對於 depends-on 循環,Spring 會直接
                     * 拋出異常
                     */
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 註冊依賴記錄
                    registerDependentBean(dep, beanName);
                    try {
                        // 加載 depends-on 依賴
                        getBean(dep);
                    } 
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // 建立 bean 實例
            if (mbd.isSingleton()) {
                /*
                 * 這裏並無直接調用 createBean 方法建立 bean 實例,而是經過 
                 * getSingleton(String, ObjectFactory) 方法獲取 bean 實例。
                 * getSingleton(String, ObjectFactory) 方法會在內部調用 
                 * ObjectFactory 的 getObject() 方法建立 bean,並會在建立完成後,
                 * 將 bean 放入緩存中。關於 getSingleton 方法的分析,本文先不展開,我會在
                 * 後面的文章中進行分析
                 */
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            // 建立 bean 實例
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                // 若是 bean 是 FactoryBean 類型,則調用工廠方法獲取真正的 bean 實例。不然直接返回 bean 實例
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            // 建立 prototype 類型的 bean 實例
            else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            // 建立其餘類型的 bean 實例
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 若是須要進行類型轉換,則在此處進行轉換。類型轉換這一塊我沒細看,就很少說了。
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }

    // 返回 bean
    return (T) bean;
}
複製代碼

主要步驟java

  • 轉換 beanName
  • 從緩存中獲取實例
  • 若是實例不爲空,且 args = null。調用 getObjectForBeanInstance 方法,並按 name 規則返回相應的 bean 實例
  • 若上面的條件不成立,則到父容器中查找 beanName 對有的 bean 實例,存在則直接返回
  • 若父容器中不存在,則進行下一步操做 – 合併 BeanDefinition
  • 處理 depends-on 依賴
  • 建立並緩存 bean
  • 調用 getObjectForBeanInstance 方法,並按 name 規則返回相應的 bean 實例
  • 按需轉換 bean 類型,並返回轉換後的 bean 實例。

2.1.3 transformedBeanName 源碼

  • 爲何要 transformedBeanName 呢?Spring 確定不會作無用功,主要有如下幾個緣由
  • 處理以字符 & 開頭的 name,防止 BeanFactory 沒法找到與 name 對應的 bean 實例
  • 處理 別名 經過別名找到最終的beanName
protected String transformedBeanName(String name) {
	return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
複製代碼

2.1.4 BeanFactoryUtils.transformedBeanName

  • 邏輯很簡單就是去除入參中的 &
/**
 * beanName 的緩存
 */
private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();
/**
 * 去除 FactoryBean 的修飾符 & 若是 name 以 「&」 爲前綴,那麼會去掉該 "&" 。
 * 例如,name = "&HelloService" ,則會是 name = "HelloService"。
 */
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { // BeanFactory.FACTORY_BEAN_PREFIX = &
        return name;
    }
    // computeIfAbsent 方法,分紅兩種狀況:
    // 1. 未存在,則進行計算執行,並將結果添加到緩存、
    // 2. 已存在,則直接返回,無需計算。
    return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
        do {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
            //BeanFactory.FACTORY_BEAN_PREFIX = "&"
        } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
        return beanName;
    });
}
複製代碼

2.1.5 SimpleAliasRegistry.canonicalName

  • 從aliasMap 獲取最終的beanName, 採用了循環主要是考慮到多層別名
<bean id="hello" class="service.Hello"/>
   <alias name="hello" alias="aliasA"/>
   <alias name="aliasA" alias="aliasB"/>
複製代碼
  • 上面的別名指向關係爲 aliasB -> aliasA -> hello,對於上面的別名配置
  • aliasMap 中數據視圖爲:aliasMap = [<aliasB, aliasA>, <aliasA, hello>]。經過下面的循環解析別名 aliasB 最終指向的 beanName
// alias -> beanName 的緩存
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

public String canonicalName(String name) {
    String canonicalName = name;
    String resolvedName;
    /*
     * 循環,從 aliasMap 中,獲取到最終的 beanName
     */
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
                canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}
複製代碼

2.1.6 getSingleton(String beanName)

  • 代碼位於 /org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java
/**  singleton 緩存map  格式爲 bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** singleton factory 緩存 map, 格式爲 bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** Set of registered singletons, containing the bean names in registration order */
private final Set<String> registeredSingletons = new LinkedHashSet<String>(256);

/** 建立中的bean */
private final Set<String> singletonsCurrentlyInCreation =
		Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

/** Names of beans currently excluded from in creation checks */
private final Set<String> inCreationCheckExclusions =
		Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

/**
 * allowEarlyReference 表示是否容許其餘 bean 引用
 */
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 從 singletonObjects 獲取實例,singletonObjects 中緩存的實例都是徹底實例化好的 bean,能夠直接使用
    Object singletonObject = this.singletonObjects.get(beanName);
    /*
     * 若是 singletonObject = null,代表還沒建立,或者還沒徹底建立好。
     */
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 從 earlySingletonObjects 中獲取提早曝光的 bean,用於處理循環引用
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 若是若是 singletonObject = null,且容許提早曝光 bean 實例,則從相應的 ObjectFactory 獲取一個原始的(raw)bean(還沒有填充屬性)
            if (singletonObject == null && allowEarlyReference) {
                // 獲取相應的工廠類
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 提早曝光 bean 實例,用於解決循環依賴
                    singletonObject = singletonFactory.getObject();
                    // 放入緩存中,若是還有其餘 bean 依賴當前 bean,其餘 bean 能夠直接從 earlySingletonObjects 取結果
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    //移除bean factory 由於已經出事花了一個原始bean放入 earlySingletonObjects
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
複製代碼

2.1.7 判斷bean是否建立中

public boolean isSingletonCurrentlyInCreation(String beanName) {
    return this.singletonsCurrentlyInCreation.contains(beanName);
}
複製代碼

2.1.8 AbstractBeanFactory.getObjectForBeanInstance

  • 從FactoryBean 獲取bean 實例
protected Object getObjectForBeanInstance(
	Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

	// 若是 name 以 & 開頭,但 beanInstance 卻不是 FactoryBean,拋出異常 
	if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
		throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
	}

	/**
	 * 1 beanInstance 是 FactoryBean 須要調用 工廠方法生成bean
	 * 2 beanInstance 是一個普通bean 直接返回
	 */
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
    	    return beanInstance;
	}

	Object object = null;
	if (mbd == null) {
	    //若是 mbd 爲空,則從緩存中加載 bean。FactoryBean 生成的單例 bean 會被緩存 在 factoryBeanObjectCache 集合中,不用每次都建立
	    object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
	    // 到這一步確定是FactoryBean
	    FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
	    // 若是mbd is null  則判斷是否存在 beanname 的 BeanDefinition,若存在 合併
	    if (mbd == null && containsBeanDefinition(beanName)) {
	        mbd = getMergedLocalBeanDefinition(beanName);
	    }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
	    object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}
複製代碼

2.1.9 org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean

/**
     * FactoryBean 也有單例和原型之分
     * 針對單例FactoryBean 生成bean 也默認是單例模式,須要放入緩存
     * 非單例的FactoryBean 生成的bean 則不會放入緩存
     * @param factory
     * @param beanName
     * @param shouldPostProcess 對bean 進行後置處理
     * @return
     */
    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        //若是factory 是單例模式
        if (factory.isSingleton() && this.containsSingleton(beanName)) {
            synchronized(this.getSingletonMutex()) {
                //緩存中獲取bean
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    //使用工廠方法建立bean
                    object = this.doGetObjectFromFactoryBean(factory, beanName);
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    } else {
                        if (shouldPostProcess) {
                            // singletonsCurrentlyInCreation 是否已有該bean Name, 若是有直接返回
                            if (this.isSingletonCurrentlyInCreation(beanName)) {
                                return object;
                            }

                            this.beforeSingletonCreation(beanName);

                            try {
                                //後置處理  
                                object = this.postProcessObjectFromFactoryBean(object, beanName);
                            } catch (Throwable var14) {
                                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", var14);
                            } finally {
                                this.afterSingletonCreation(beanName);
                            }
                        }
                        // singletonObjects map 是否包含 beanName
                        if (this.containsSingleton(beanName)) {
                            //若是包含則 把 FactoryBean 建立的bean 緩存到 factoryBeanObjectCache
                            //factoryBeanObjectCache 定義於 org.springframework.beans.factory.support.FactoryBeanRegistrySupport
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }

                return object;
            }
        } else {
            //非單例模式 直接經過工廠方法獲取
            Object object = this.doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = this.postProcessObjectFromFactoryBean(object, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var17);
                }
            }

            return object;
        }
    }

    private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
        Object object;
        try {
            //這塊沒太懂
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = this.getAccessControlContext();
                try {
                    object = AccessController.doPrivileged(factory::getObject, acc);
                } catch (PrivilegedActionException var6) {
                    throw var6.getException();
                }
            } else {
                //直接經過工廠方法獲取
                object = factory.getObject();
            }
        } catch (FactoryBeanNotInitializedException var7) {
            throw new BeanCurrentlyInCreationException(beanName, var7.toString());
        } catch (Throwable var8) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8);
        }

        if (object == null) {
            if (this.isSingletonCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");
            }

            object = new NullBean();
        }

        return object;
    }
複製代碼

待完善中spring

相關文章
相關標籤/搜索