首頁 > 軟體

Spring Bean是如何初始化的詳解

2022-03-22 16:00:36

前言

做Java都有很多年了,一直有一個疑惑: Spring 如何初始化bean,怎麼呼叫反射範例化物件的,自己動手來解除這個疑惑。 過去我認為spring bean物件範例化一直都是由BeanPostProcessor介面實現類去做的,我就是不知道具體那個實現類,下面就去驗證下這個猜想。

三級快取

為什麼面試官特別喜歡問建立bean的三級快取,主要是因為bean建立都是伴隨著三級快取之間的轉換完成的,物件不同狀態分別存在不同快取中,下面我會在分析程式碼時,順便支援物件如何在快取中流轉的。 先了解下spring 三級快取。

    /** 一級快取 用於存放完全可以使用單例bean,也就是初始化完成並且注入所有依賴 */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 二級快取 過早暴露單例物件,此時bean剛剛完成初始化,未完成屬性注入和執行 init 方法 */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

	/** 三級快取  裝載建立bean的工廠物件 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16)

三級快取主要作用: 建立物件ObjectFactory首先放入三級換快取中,當呼叫getObject 建立範例時,會將建立好物件加入二級快取中,並且刪除三級中快取,當物件已經完成初始化方法和屬性注入,再將快取新增到一級快取中,並且刪除二級快取。

doGetBean

從源頭開始找,所有spring bean 初始化都是由AbstractBeanFactory.doGetBean方法實現的。下面我將原始碼減除臃腫部分,貼出來。

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
        //name 字首處理  beanFactory beanName 帶有&開頭
		String beanName = transformedBeanName(name);
		Object beanInstance;
        //從三級快取去取bean,三級中都沒有則返回null,說明物件還沒有建立
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) { //如果快取中bean 是FactoryBean範例,要通過介面獲取到實際bean
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else { 
             //判斷bean物件標記是否正在建立中,如果正在建立中則不應該繼續下去,出現依賴迴圈就會出現這個錯誤
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			BeanFactory parentBeanFactory = getParentBeanFactory();
            // 檢查父容器是否存在,嘗試從父容器中獲取
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) { //快取中標記beanName 正在被建立
				markBeanAsCreated(beanName);
			}
			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
					.tag("beanName", name);
			try {
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {  //bean 中@DependsOn 資訊,用於標記bean之間初始化順序,優先建立@DependsOn   中bean
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

			     //建立單例物件
				if (mbd.isSingleton()) { //重點就在這裡範例化物件  ,getSingleton 就是在這裡將建立完成物件加入到一級快取中
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) 
							destroySingleton(beanName);
							throw ex;
						}
					});
                    //如果生成bean 是FactoryBean ,再獲取真正的物件
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
                //作用域 = prototype,因為不會放入快取中,每次獲取都要重新建立
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else { // session request 這些作用域,由作用域容器去管理這些物件
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					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, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
			}
			catch (BeansException ex) {
				beanCreation.tag("exception", ex.getClass().toString());
				beanCreation.tag("message", String.valueOf(ex.getMessage()));
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
			finally {
				beanCreation.end();
			}
		}
                //返回初始化成功的物件,一個物件初始化就這樣完成的了  
		return adaptBeanInstance(name, beanInstance, requiredType);  
	}

大概總結一下上面程式碼流程:

  • 先從三級快取中獲取,如果快取中都沒有。再去判斷是否存在父容器,從父容器中獲取。沒有正式進入bean 初始化流程,先根據beanName 獲取到RootBeanDefinition,bean類元資訊、先處理dependsOn中bean,保證bean依賴的建立順序,下面會說明org.springframework.context.annotation.@DependsOn這個註解。下一步按照不同scope 進行bean 物件初始化。初始化流程就是這樣,我們將目光放在單例bean 如何範例化,集中關注AbstractAutowireCapableBeanFactory.createBean 獲取註冊一個單例物件

@DependsOn 註解意思是範例化某個物件依賴於某一個範例化,但是不需要持有這個範例物件。比如bean A上 需要依賴bean b才能範例化,但是bean b 不需要作為他的屬性,常常用於不同範例範例化順序標記。

看下getSingleton方法

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) { //標記bean 是否在銷燬
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
				}
				catch (BeanCreationException ex) {
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject); //就是在這裡刪除二三級快取,提交到一級快取
				}
			}
			return singletonObject;
		}
	}
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

新增到一級快取則說明bean已經完成範例化,可以正常使用了。下面看下如何進行範例化和屬性注入的。

createBean

下面進入AbstractAutowireCapableBeanFactory.createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
		RootBeanDefinition mbdToUse = mbd;
        //克隆一份mbd => mbdToUse
		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.
                //通過BeanPostProcessors 增強返回一個代理物件,這個生成AOP的代理物件,使用多個BeanPostProcessors來處理
			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);
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

這裡邏輯就比較簡單了 ,克隆一份RootBeanDefinition用於初始化物件,resolveBeforeInstantiation 主要用於初始化代理物件情況,主要使用BeanPostProcessor子類InstantiationAwareBeanPostProcessor實現方法去實現物件初始化,並且在範例化成功後在呼叫後置方法進行物件依賴注入,這裡可以看見此方法返回物件直接跳出方法棧,這裡可以看出單例和代理物件還是有區別的。單例物件初始化就在doCreateBean 實現了

doCreateBean

下面就是AbstractAutowireCapableBeanFactory.doCreateBean非常接近物件如何範例化的了

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) { 
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);  //這個就是範例化方法
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// 使用BeanDefinitionPostProcessors 對合並bean進行範例化 
		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;
			}
		}

		// 這裡就需要用到上面說的三級快取知識了
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName)); //是否放入第三級快取中
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); //將已經範例化的物件加入到第三級快取 singletonFactories 
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper); //對屬性進入注入,下面會具體分析的
			exposedObject = initializeBean(beanName, exposedObject, mbd); //執行初始化方法,或者注入Aware 介面bean
		}
		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);
			}
		}

		//下面程式碼省略
               //主要就是對設定了DisposableBean 介面銷燬勾點方法處理
	}

這裡程式碼主要分成三部分

  • 初始化範例,建立物件完成,並且新增到3級快取。第3級快取常常用於儲存代理物件,因為有些類需要動態代理方法,需要生成代理物件,會委派給第三級快取方法ObjectFactroy去實現的,普通物件如果不需要會直接返回。
  • 對範例化bean進行屬性注入
  • 執行初始化方法,DisposableBean介面加入到disposableBeans容器中

instantiateBean

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {// 有實現Supplier 介面,由instanceSupplier.get() 方法建立範例
			return obtainFromSupplier(instanceSupplier, beanName);
		}

                //factoryName  使用工廠模式建立bean,呼叫工廠方法去建立,這個支援靜態方法和factoryBean.invoke
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;   //標記建構函式是否需要引數
		boolean autowireNecessary = false;  //標記構造方法的引數是否使用注入方式
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) { 
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
                               //使用建構函式注入方式範例化
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
                               //範例化物件
				return instantiateBean(beanName, mbd);
			}
		}

		// 獲取建構函式引數
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

範例化方法instantiateBean最終會呼叫SimpleInstantiationStrategy.instantiate 進行範例化

instantiate

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse = clazz.getDeclaredConstructor(); //獲取建構函式
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse); //呼叫建構函式進行範例化
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

instantiateClass

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);  //呼叫構造器進行初始化
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

這裡要注意下先判斷bean是否有方法重寫的,沒有則使用反射生成的構造器,有就使用gclib方式建立代理物件,具體實現方式就在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate,有興趣同學可以去學習下。 到此一個簡單bean範例化完成了。

注入

下面進入IOC另一個特點,bean注入,先從AbstractAutowireCapableBeanFactory.populateBean方法開始

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
              //通過InstantiationAwareBeanPostProcessors.postProcessAfterInstantiation 如果返回true,目標範例內部的返回值會被populate,否則populate這個過程會被忽視
            //翻譯說如果返回true可以執行欄位注入 真的6666啊
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
                //獲取注入方式分佈有4種
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();  
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
            //依賴方式,模式都是沒有型別檢查,這種依賴方式一般都是xml 設定用得比較多,沒有設定這裡都是返回false
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); /

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);  //獲取註解標註需要注入方法或者是欄位,並且進行注入
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

小知識點: AutowireCapableBeanFactory.AUTOWIRE_NO 表明不會對當前Bean進行外部類的注入,常規使用@Autowire、@Resource 都是這型別 剩下三種都是通過xml 或者 AutowireCapableBeanFactory.autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) 進行設定autowireMode 。

根據上面程式碼可以知道主流程bean注入都是由InstantiationAwareBeanPostProcessor 進行處理的,簡單說明介面方法

方法描述
postProcessBeforeInitialization方法是最 先執行的方法,它在目標物件範例化之前呼叫,該方法的返回值型別是Object,我們可以返回任何型別的值。由於這個時候目標物件還未範例化,所以這個返回值可以用來代替原本該生成的目標物件的範例(比如代理物件)。如果該方法的返回值代替原本該生成的目標物件,後續只有postProcessAfterInitialization方法會呼叫,其它方法不再呼叫;否則按照正常的流程走
postProcessAfterInitialization方法在目標物件範例化之後呼叫,這個時候物件已經被範例化,但是該範例的屬性還未被設定,都是null。因為它的返回值是決定要不要呼叫postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果返回true,postProcessPropertyValues就會被執行
postProcessPropertyValues對bean屬性值賦值後呼叫,對屬性值的修改。如果postProcessAfterInstantiation方法返回false,該方法可能不會被呼叫。可以在該方法內對屬性值進行修改
postProcessPropertiesBean屬性賦值就是呼叫這個方法的

InstantiationAwareBeanPostProcessor 介面實現類主要分3個

  • ConfigurationClassPostProcessor:看類名就知道處理@Configuration範例化,並沒有屬性注入邏輯,不詳講略過。
  • CommonAnnotationBeanPostProcessor:這個類就是實現bean注入,但是是實現JSR-250 註解、@Resource,@EJB、@WebServiceRef,@WebServiceContext,@PostConstrusct、@PreDestory這些註解實現。
  • AutowiredAnnotationBeanPostProcessor:實現 @Autowired、@Value注入,並且支援JSR-330's @Inject,主要分析這個類就可以知道bean 注入的。

AutowiredAnnotationBeanPostProcessor分析

	private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
	@SuppressWarnings("unchecked")
	public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

在初始化時就將支援註解加入集合中,再使用掃描器去掃描方法、構造器、欄位,如果有這些註解就進行注入。

看下怎麼判斷是否需要注入的

	@Nullable
	private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
		MergedAnnotations annotations = MergedAnnotations.from(ao);
		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
			MergedAnnotation<?> annotation = annotations.get(type);
			if (annotation.isPresent()) {
				return annotation;
			}
		}
		return null;
	} 

AccessibleObject 是Method、Field、Constructor 父類別。

postProcessProperties 如何實現bean注入的

	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
              //獲取需要注入欄位,方法
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs); //注入
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}
       //下面就行獲取InjectionMetadata 
	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// 快速從快取中獲取,如果沒有加鎖去解析,然後在結果放入快取中
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) { 
			synchronized (this.injectionMetadataCache) { //雙重檢查
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					metadata = buildAutowiringMetadata(clazz); 
					this.injectionMetadataCache.put(cacheKey, metadata); 
				}
			}
		}
		return metadata;
	}
  • InjectionMetadata 主要是集合bean需要被注入型別,因為已經解析過bean Class資訊了,相當於解析結果裝起來

看下如何去掃描方法、欄位的

 	private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
       //從給定註解中判斷class 是否攜帶這個註解
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { 
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            //遍歷所有Field,找出掃描的註解,特意標註不支援static 修飾field 
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
                     // 獲取註解內 required 值
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                //獲取方法上橋接方法,因為泛型型別擦除,要對橋接方法進行安全檢查,防止在呼叫是出現異常
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
                //獲取註解
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
               //方法安全檢查
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) { //不支援靜態方法注入
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});
           // 這樣寫是為了後面加入排在佇列前面,父類別屬性優先於子類
			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class); //這裡寫得很好,向上解析父類別,直到是Object 為止

		return InjectionMetadata.forElements(elements, clazz);
	}

邏輯非常簡單,就是根據給定註解去class獲取指定的註解,從而獲取到需要注入型別,但是幾行簡單的程式碼可以看出強大編碼能力,學習了


IT145.com E-mail:sddin#qq.com