Spring @Autowired 註解自動注入流程是怎麼樣?

面試中碰到面試官問:”Spring 註解是如果工作的?“,當前我一驚,完了這不觸及到我的知識誤區了嗎?,還好我機智,靈機一動回了句:Spring 註解的工作流程倒還沒有看到,但是我知道@Autowired註解的工作流程,後面不用說了一頓巴拉,面試官都連連點頭。

面試中要活用轉移話題,要避免回答 ”不知道“,要引導面試官掉入你擅長的技術,然後纔有機會教他作人。

@Autowired 相關的類

@Autowired 註解的主要功能就是完成自動注入,使用也非常簡單(Spring都安排好了),但是要想知道 @Autowired 註解的內部現實,就需要看一下Spring源碼了。接下來一步步的解剖 @Autowired 的實現原理,首先理一下與 @Autowired 註解相關的類,然後一步步的跟蹤源碼,直到理解 @Autowired 的原理。

AutowiredAnnotationBeanPostProcessor 類

AutowiredAnnotationBeanPostProcessor是實現 @Autowired 功能的主要類,它有一些方法是會用解析 @Autowired 註解並實現自動注入的功能,下面是它的繼承圖:

從上圖可以發現 AutowiredAnnotationBeanPostProcessor 最上層是 BeanPostProcessor 是一個後處理器,當然除了後處理器外中間還有InstantiationAwareBeanPostProcessorMergedBeanDefinitionPostProcessor

InstantiationAwareBeanPostProcessor 接口

postProcessBeforeInstantiation方法

在Bean實例化之前調用,可以返回一個Bean實例,默認返回null

@Nullabledefault Object postProcessBeforeInstantiation(Class<?> beanClass, String 
beanName) throws BeansException {      return null;}

postProcessAfterInstantiation方法

在Bean創建完成後,設置屬性之前調用。

default boolean postProcessAfterInstantiation(Object bean, String 
beanName) throws BeansException {      return true;}

postProcessProperties方法

@Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object 
bean, String beanName)            throws BeansException {      return null;}

Bean創建完後,設置屬性之前調用

先記住 InstantiationAwareBeanPostProcessor 接口,後面會跟蹤調用它的地方,就很容易理解了。

MergedBeanDefinitionPostProcessor

MergedBeanDefinitionPostProcessor 也是一個繼承 BeanPostProcessor 接口的後處理器,它的主要作用就是可以處理操作BeanDefinition對象,由於Bean的實例化是通過 BeanDefinition 的, 通過操作BeanDefinition ,這樣可以使Bean的實例化時發生一些變化。

MergedBeanDefinitionPostProcessor 只有兩個方法

postProcessMergedBeanDefinition方法

void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, 
Class<?> beanType, String beanName);

Bean的BeanDefinition 被合併後調用此方法。

resetBeanDefinition

default void resetBeanDefinition(String beanName) {}

當一個BeanDefinition被重置後調用 。

AutowireCapableBeanFactory 接口

AutowireCapableBeanFactory繼承自BeanFactory,除了提供基礎的Bean操作外,從接口的名字就可以推斷出的它還有自動注入的能力。AutowireCapableBeanFactory 提供四種注入模型:

  • AUTOWIRE_NO: 沒有顯示的定義注入模型
  • AUTOWIRE_BY_NAME: 通過Bean名稱注入
  • AUTOWIRE_BY_TYPE: 通過Bean的類型注入
  • AUTOWIRE_CONSTRUCTOR:通過Bean的構造方法注入

AutowireCapableBeanFactory 接口有不少方法,但大部分都是跟自動注入的相關。@Autowired 的主要功能就是在Bean實例化後,爲其設置屬性,所以在 AutowireCapableBeanFactory 接口有一個 createBean方法,用於創建Bean並設置Bean的屬性:

<T> T createBean(Class<T> beanClass) throws BeansException;

createBean方法,它的調用時機是創建Bean的時候,稍後會說到它的調用時機。

AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory 繼承 AbstractBeanFactory並實現了AutowireCapableBeanFactory接口,所以它也實現了AutowireCapableBeanFactory中的createBean方法。

public <T> T createBean(Class<T> beanClass) throws BeansException {     

// Use prototype bean definition, to avoid registering bean as dependent bean.      

RootBeanDefinition bd = new RootBeanDefinition(beanClass);      
bd.setScope(SCOPE_PROTOTYPE);     

bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());      

return (T) createBean(beanClass.getName(), bd, null);}

Bean創建的生命週期

通過了解Bean創建的生命週期,纔可以將上面與 @Autowired 相關的類串起來,首先這裏不會過多的介紹Bean的創建細節,只關注自動注入相關的代碼。

Bean的創建過程

Spring中默認的Bean都是懶加載的,所以一個Bean的創建會從調用getBean方法開始,如果不考慮緩存、上層容器的情況,Bean的創建會經過以下方法:

  • getBean:BeanFactory的方法,獲取Bean實例
  • doGetBean:獲取Bean的實例,獲取順序依次爲:單例池、父容器,如果從以上2種途徑都沒獲取到Bean實例就會創建新的
  • createBean:創建 Bean,這裏的createBean,跟上面介紹的是一回事
  • doCreateBean:創建Bean實例
  • populateBean:設置Bean屬性

以上流程中的getBeandoGetBean不多作說明了, 重點關注createBean前面提到AbstractAutowireCapableBeanFactory.createBean方法,所以說你在調用getBean方法獲取Bean的實例時,如果這個Bean實例還沒有被創建,那麼createBean就會被調用。

通過簡單的說明Bean創建的生命週期,就能找到 @Autowired 註解實現的入口,接下來再繼續跟蹤createBean方法。

收集註入元信息

收集註入元信息的步驟的,其實就是調用AutowiredAnnotationBeanPostProcessor類方法來實現的。

Bean 創建之前

以下是createBean方法,在Bean創建之前調用postProcessBeforeInstantiation的地方。爲是閱讀方便省略了一些代碼,大致的流程就是:

  • 首先調用 resolveBeforeInstantiation 方法,執行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法
  • 如果postProcessBeforeInstantiation返回Bean實例那麼直接返回這個實例,如果返回nul 繼續調用doCreateBean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
 
   ...

   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) {
        ...
   }
   
     ...
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    ...
   
   ...
 }
   
 @Nullable
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;
}

這裏 AutowiredAnnotationBeanPostProcessor 的 postProcessBeforeInstantiation 的方法會被調用,由於AutowiredAnnotationBeanPostProcessor 並沒有重寫這個方法,所以什麼都不做。

操作 BeanDefinition

上面說過 postProcessBeforeInstantiation 方法返回 null 的話會繼續執行doCreateBean方法:

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


   // 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;
      }
   }

  ...
 populateBean(beanName, mbd, instanceWrapper);
 ...
 

在 doCreateBean 方法中,會調用調用applyMergedBeanDefinitionPostProcessors方法:

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }

MergedBeanDefinitionPostProcessor接口上面提到到的,AutowiredAnnotationBeanPostProcessor 實現了這個接口所以直接進入到 AutowiredAnnotationBeanPostProcessor 中的 postProcessMergedBeanDefinition方法:


@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}
查找注入元數據

接着繼續進入到findAutowiringMetadata,findAutowiringMetadata 會調用buildAutowiringMetadata方法創建注入元數據,然後將元數據緩存到injectionMetadataCache屬性中:


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());
   // Quick check on the concurrent map first, with minimal locking.
   InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
   if (InjectionMetadata.needsRefresh(metadata, clazz)) {
      synchronized (this.injectionMetadataCache) {
         metadata = this.injectionMetadataCache.get(cacheKey);
         if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            ...
            metadata = buildAutowiringMetadata(clazz);
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}
創建注入元數據

仔細查看buildAutowiringMetadata方法的實現,它會反射類的方法和屬性,同時還會向上查找父類,然後生成InjectionMetadata

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		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<>();

			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;
					}
					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);

		return InjectionMetadata.forElements(elements, clazz);
	}

小結

收集註入元數據過程,首先調用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法,然後調用findAutowiringMetadata方法查找元數據,如果找到相應類的注入元數據 ,就會調用buildAutowiringMetadata方法創建InjectionMetadata,最後將新創建的注入元數據保存在injectionMetadataCache緩存起來。

設置Bean屬性

收信完注入元數據後,Bean的屬性還是沒有注入的,還需要將執行屬性注入。還是在doCreateBean方法中,收集完注入元數據後,緊接着會調用populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
   if (pvs == null) {
      pvs = mbd.getPropertyValues();
   }
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            if (filteredPds == null) {
               filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               return;
            }
         }
         pvs = pvsToUse;
      }
   }
   }
}

可以看到在populateBean中會調用InstantiationAwareBeanPostProcessor.postProcessProperties方法,由於已經知道 AutowiredAnnotationBeanPostProcessor 是實現 InstantiationAwareBeanPostProcessor 的,所以可以直接查看實現方法:

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
   }
   return pvs;
}

postProcessProperties就很簡單的,查找 InjectMetadata,然後調用 InjectMetadata.inject方法。到這裏其實就已經知道@Autowire的實現機制了,接下來就是根據InjectionMetadata中的信息實現屬性注入了。

如果需要深入研究的話,有興趣的還可以繼續往下看。

總結

本文大致講解了 @Autowire 相關的類與實現的機制,@Autowire 註解的實現主要是理解AutowiredAnnotationBeanPostProcessor類,還有收集註入元數據、設置注入屬性的調用時機。

通過查看AutowiredAnnotationBeanPostProcessor類源碼,相信你也可以自定義注入功能。

本人知識水平有限,如有錯誤,謝謝大家指正。

歡迎關注我的公衆號:架構文摘,獲得獨家整理120G的免費學習資源助力你的架構師學習之路!

公衆號後臺回覆arch028獲取資料:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章