Spring Ioc 之 Bean的加載(四):createBean()

上一篇文章Spring Ioc 之 Bean的加載(三):各個 scope 的 Bean 建立 咱們分析了各個做用域Bean的建立大致流程。這篇文章咱們來分析如下建立Bean的關鍵方法 createBean()java

createBean()

代碼:spring

//AbstractAutowireCapableBeanFactory.java

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable 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.
	//判斷須要建立的Bean是否能夠實例化,便是否能夠經過當前的類加載器加載
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	//校驗和準備Bean中的方法覆蓋
	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.
		//若是Bean配置了初始化前和初始化後的處理器,則試圖返回一個須要建立Bean的代理對象
		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);
	}

	try {
		//建立Bean的入口
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isDebugEnabled()) {
			logger.debug("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	catch (BeanCreationException ex) {
		// A previously detected exception with proper bean creation context already...
		throw ex;
	}
	catch (ImplicitlyAppearedSingletonException ex) {
		// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
	}

這段代碼分爲如下幾個步驟:緩存

  1. 判斷須要建立的Bean是否能夠實例化,便是否能夠經過當前的類加載器加載app

  2. 校驗和準備Bean中的方法注入ide

  3. 若是Bean配置了初始化前和初始化後的處理器,則試圖返回一個須要建立Bean的代理對象函數

  4. 建立Beanpost

第1步

主要是獲取bean的class,並設置到BeanDefinition中this

第2步

主要是處理方法注入
代碼:.net

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
	// Check that lookup methods exists.
	//檢測是否存在方法注入,並循環預處理方法注入
	if (hasMethodOverrides()) {
		Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
		synchronized (overrides) {
		        //遍歷處理
			for (MethodOverride mo : overrides) {
				prepareMethodOverride(mo);
			}
		}
	}
	}

prepareMethodOverride(mo):debug

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
        // 統計注入的方法個數   
	int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
	if (count == 0) {
		throw new BeanDefinitionValidationException(
				"Invalid method override: no method with name '" + mo.getMethodName() +
				"' on class [" + getBeanClassName() + "]");
	}
        // 若是爲1,則將注入方法標記爲未重載
	// 注意:當有多個重載方法時,爲了肯定調用哪一個具體的方法,Spring對重載方法的參數解析是很複雜的
	// 因此,若是注入方法沒有被重載這裏就將其標記,省去了對方法參數的解析過程,直接調用便可
	else if (count == 1) {
		// Mark override as not overloaded, to avoid the overhead of arg type checking.
		mo.setOverloaded(false);
	}
	}

代碼讀到這裏,你們可能有疑問,從代碼上看明明是處理的方法重載,可是爲何處理的是方法注入呢?並且若是咱們在bean裏設置幾個方法重載的話,hasMethodOverrides()方法返回的是false。若是咱們打開 AbstractBeanDefinition 類的 hasMethodOverrides() 方法,就能打消咱們以前的疑問。

public boolean hasMethodOverrides() {
		return (this.methodOverrides != null && !this.methodOverrides.isEmpty());
	}

其中methodOverrides是作什麼的呢?經過類名AbstractBeanDefinition咱們能夠發現,該類是BeanDefinition的一個子類,那麼它保存的應該是咱們解析到的beanDefinition,spring在解析配置文件的時候,若是發現配置了replace-method或者lookup-method那麼,就會對應的標籤解析,並存入到 AbstractBeanDefinition 的 methodOverrides 屬性中,那麼當bean實例化的時候,若是檢測到了methodOverrides屬性不爲空,則動態的爲當前bean生成代理並使用相應的攔截器對bean作處理,這裏你們只要把概念搞清楚便可。

第3步

主要是對bean前置後置處理器的處理,給 BeanPostProcessors 後置處理器一個返回代理對象的機會
詳細代碼:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		// Make sure bean class is actually resolved at this point.
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
	}

若是代理對象不爲空,則直接返回代理對象,這一步驟有很是重要的做用,Spring 後續實現 AOP 就是基於這個地方判斷的。
這個方法核心就在於 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 兩個方法,before 爲實例化前的後處理器應用,after 爲實例化後的後處理器應用。

第4步

doCreateBean()
建立Bean

//真正建立Bean的方法
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {

	// Instantiate the bean.
	//BeanWrapper是對Bean的包裝,其接口中所定義的功能很簡單包括設置獲取被包裝的對象,獲取被包裝bean的屬性描述器
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
	        //單例模式,刪除factoryBean緩存
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
	        //使用合適的實例化策略來建立Bean:工廠方法、構造函數自動注入、簡單初始化
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	//從包裝類中獲取實例化的Bean
	final Object bean = instanceWrapper.getWrappedInstance();
	//獲取實例化對象的類型
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}

	// Allow post-processors to modify the merged bean definition.
	//檢查是否有後置處理
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
			        //調用PostProcessor後置處理器,修改 BeanDefinition
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.postProcessed = true;
		}
	}

	// 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, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	//Bean對象的初始化,依賴注入在此觸發
	//這個exposedObject在初始化完成以後返回做爲依賴注入完成後的Bean
	Object exposedObject = bean;
	try {
		//將Bean實例對象封裝,而且Bean定義中配置的屬性值賦值給實例對象
		populateBean(beanName, mbd, instanceWrapper);
		//初始化Bean對象
		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);
		}
	}

	if (earlySingletonExposure) {
		//獲取指定名稱的已註冊的單例模式Bean對象
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			//根據名稱獲取的已註冊的Bean和正在實例化的Bean是同一個
			if (exposedObject == bean) {
				//當前實例化的Bean初始化完成
				exposedObject = earlySingletonReference;
			}
			//當前Bean依賴其餘Bean,而且當發生循環引用時不容許新建立實例對象
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				String[] dependentBeans = getDependentBeans(beanName);
				Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
				//獲取當前Bean所依賴的其餘Bean
				for (String dependentBean : dependentBeans) {
					//對依賴Bean進行類型檢查
					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.
	//註冊完成依賴注入的Bean
	try {
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}

	return exposedObject;
	}

代碼很長,不過別慌,咱們來按步驟分析一波

  1. 若是是單例模式,從factoryBeanInstanceCache 緩存中獲取BeanWrapper 實例對象並刪除緩存
  2. 調用 createBeanInstance() 實例化 bean
    (主要是將 BeanDefinition 轉換爲 BeanWrapper)
  3. 後置處理
  4. 單例模式的循環依賴處理
  5. 初始化 bean 實例對象
    (屬性填充)
  6. 依賴檢查
  7. 註冊 DisposableBean

doCreateBean() 完成 bean 的建立和初始化工做,內容太多,比較複雜,這裏只列出大體流程,接下來咱們將分幾篇文章來分別闡述相關內容。

相關文章
相關標籤/搜索