死磕Spring之IoC篇 - @Autowired 等註解的實現原理

月圓吖發表於2021-03-08

該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 Spring 原始碼分析 GitHub 地址 進行閱讀

Spring 版本:5.1.14.RELEASE

開始閱讀這一系列文章之前,建議先檢視《深入瞭解 Spring IoC(面試題)》這一篇文章

該系列其他文章請檢視:《死磕 Spring 之 IoC 篇 - 文章導讀》

@Autowired 等註解的實現原理

在上一篇《Bean 的屬性填充階段》文章中講到,在建立一個 Bean 的例項物件後,會對這個 Bean 進行屬性填充。在屬性填充的過程中,獲取到已定義的屬性值,然後會通過 InstantiationAwareBeanPostProcessor 對該屬性值進行處理,最後通過反射機制將屬性值設定到這個 Bean 中。在 Spring 內部有以下兩個 InstantiationAwareBeanPostProcessor 處理器:

  • AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 註解標註的屬性,獲取對應屬性值
  • CommonAnnotationBeanPostProcessor,會解析 @Resource 註解標註的屬性,獲取對應的屬性值

本文將會分析這兩個處理器的實現,以及涉及到的相關物件

這兩個處理器在哪被註冊?

在前面的《解析自定義標籤(XML 檔案)》《BeanDefinition 的解析過程(面向註解)》文章中可以知道,在 XML 檔案中的 <context:component-scan /> 標籤的處理過程中,會底層藉助於 ClassPathBeanDefinitionScanner 掃描器,去掃描指定路徑下符合條件(@Component 註解)的 BeanDefinition 們,關於 @ComponentScan 註解的解析也是藉助於這個掃描器實現的。掃描過程如下:

// ClassPathBeanDefinitionScanner.java
public int scan(String... basePackages) {
    // <1> 獲取掃描前的 BeanDefinition 數量
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

    // <2> 進行掃描,將過濾出來的所有的 .class 檔案生成對應的 BeanDefinition 並註冊
    doScan(basePackages);

    // Register annotation config processors, if necessary.
    // <3> 如果 `includeAnnotationConfig` 為 `true`(預設),則註冊幾個關於註解的 PostProcessor 處理器(關鍵)
    // 在其他地方也會註冊,內部會進行判斷,已註冊的處理器不會再註冊
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    // <4> 返回本次掃描註冊的 BeanDefinition 數量
    return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

在第 <3> 步會呼叫 AnnotationConfigUtils 的 registerAnnotationConfigProcessors(BeanDefinitionRegistry) 方法,如下:

// AnnotationConfigUtils.java
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}

/**
 * Register all relevant annotation post processors in the given registry.
 * @param registry the registry to operate on
 * @param source the configuration source element (already extracted)
 * that this registration was triggered from. May be {@code null}.
 * @return a Set of BeanDefinitionHolders, containing all bean definitions
 * that have actually been registered by this call
 */
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    // 處理 Spring 應用上下文中的配置類
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 處理 @Autowired 以及 @Value 註解
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // (條件啟用)處理 JSR-250 註解 @Resource,如 @PostConstruct、@PreDestroy 等
    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Processor 物件(條件啟用)處理 JPA 註解場景
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition();
        try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                    AnnotationConfigUtils.class.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 處理標註 @EventListener 的 Spring 事件監聽方法
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    // 用於 @EventListener 標註的事件監聽方法構建成 ApplicationListener 物件
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

在這個方法中可以看到會註冊 AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor 兩個處理器,然後在 Spring 應用上下文重新整理階段會將其初始化並新增至 AbstractBeanFactory 的 beanPostProcessors 集合中,那麼接下來我們先來分析這兩個處理器

回顧 Bean 的建立過程

第一步:回到《Bean 的建立過程》文章中的“對 RootBeanDefinition 加工處理”小節,會呼叫這個方法:

// AbstractAutowireCapableBeanFactory.java
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 的 postProcessMergedBeanDefinition 方法對 RootBeanDefinition 進行加工處理,例如:

  • AutowiredAnnotationBeanPostProcessor,會先解析出 @Autowired@Value 註解標註的屬性的注入元資訊,後續進行依賴注入
  • CommonAnnotationBeanPostProcessor,會先解析出 @Resource 註解標註的屬性的注入元資訊,後續進行依賴注入,它也會找到 @PostConstruct@PreDestroy 註解標註的方法,並構建一個 LifecycleMetadata 物件,用於後續生命週期中的初始化和銷燬

第二步:回到《Bean 的建立過程》文章中的“屬性填充”小節,該過程會進行下面的處理:

// <5> 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }

        // <5.1> 遍歷所有的 BeanPostProcessor
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 如果為 InstantiationAwareBeanPostProcessor 型別
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // <5.2> 呼叫處理器的 `postProcessProperties(...)` 方法,對 `pvs` 進行後置處理
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                // <5.3> 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要相容老版本
                if (pvsToUse == null) {
                    // <5.3.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊)
                    if (filteredPds == null) {
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    }
                    // <5.3.2> 呼叫處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行後置處理
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    // <5.3.3> 如果處理後的 PropertyValues 物件為空,直接 `return`,則不會呼叫後面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
                    if (pvsToUse == null) {
                        return;
                    }
                }
                // <5.4> 將處理後的 `pvsToUse` 複製給 `pvs`
                pvs = pvsToUse;
            }
        }
    }

這裡不會呼叫所有 InstantiationAwareBeanPostProcessor 的 postProcessProperties 方法對 pvs(MutablePropertyValues)屬性值物件進行處理,例如:

  • AutowiredAnnotationBeanPostProcessor,會根據前面解析出來的 @Autowired@Value 註解標註的屬性的注入元資訊,進行依賴注入
  • CommonAnnotationBeanPostProcessor,會根據前面解析出來的 @Resource 註解標註的屬性的注入元資訊,進行依賴注入

可以看到@Autowired@Value@Resource 註解的實現就是基於這兩個處理器實現的,接下來我們來看看這兩個處理器的具體實現

AutowiredAnnotationBeanPostProcessor

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor,主要處理 @Autowired@Value 註解進行依賴注入

體系結構

死磕Spring之IoC篇 - @Autowired 等註解的實現原理

可以看到 AutowiredAnnotationBeanPostProcessor 實現了 MergedBeanDefinitionPostProcessor 和 InstantiationAwareBeanPostProcessor 兩個介面

構造方法

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
      implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

   /**
    * 儲存需要處理的註解
    */
   private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

   private String requiredParameterName = "required";

   private boolean requiredParameterValue = true;

   private int order = Ordered.LOWEST_PRECEDENCE - 2;

   @Nullable
   private ConfigurableListableBeanFactory beanFactory;

   private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

   private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);

   /**
	* 快取需要注入的欄位元資訊
	*/
   private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

   /**
    * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
    * standard {@link Autowired @Autowired} annotation.
    * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
    * if available.
    */
   @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.
      }
   }
}

可以看到會新增 @Autowired@Value 兩個註解,如果存在 JSR-330 的 javax.inject.Inject 註解,也是支援的

postProcessMergedBeanDefinition 方法

postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) 方法,找到 @Autowired@Value 註解標註的欄位(或方法)的元資訊,如下:

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 找到這個 Bean 所有需要注入的屬性(@Autowired 或者 @Value 註解)
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

直接呼叫 findAutowiringMetadata(...) 方法獲取這個 Bean 的注入元資訊物件

1. findAutowiringMetadata 方法
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
    // Fall back to class name as cache key, for backwards compatibility with custom callers.
    // 生成一個快取 Key
    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)) { // 加鎖,再判斷一次
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                // 構建一個需要注入的元資訊物件
                metadata = buildAutowiringMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

首先嚐試從快取中獲取這個 Bean 對應的注入元資訊物件,沒有找到的話則呼叫 buildAutowiringMetadata(final Class<?> clazz) 構建一個,然後再放入快取中

2. buildAutowiringMetadata 方法
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        // <1> 建立 `currElements` 集合,用於儲存 @Autowired、@Value 註解標註的欄位
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

        // <2> 遍歷這個 Class 物件的所有欄位
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            // <2.1> 找到該欄位的 @Autowired 或者 @Value 註解,返回 `ann` 物件,沒有的話返回空物件,則直接跳過不進行下面的操作
            AnnotationAttributes ann = findAutowiredAnnotation(field);
            if (ann != null) {
                // <2.2> 進行過濾,static 修飾的欄位不進行注入
                if (Modifier.isStatic(field.getModifiers())) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation is not supported on static fields: " + field);
                    }
                    return;
                }
                // <2.3> 獲取註解中的 `required` 配置
                boolean required = determineRequiredStatus(ann);
                // <2.4> 根據該欄位和 `required` 構建一個 AutowiredFieldElement 物件,新增至 `currElements`
                currElements.add(new AutowiredFieldElement(field, required));
            }
        });

        // <3> 遍歷這個 Class 物件的所有方法
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            // <3.1> 嘗試找到這個方法的橋接方法,沒有的話就是本身這個方法
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            // <3.2> 如果是橋接方法則直接跳過
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            // <3.3> 找到該方法的 @Autowired 或者 @Value 註解,返回 `ann` 物件,沒有的話返回空物件,則直接跳過不進行下面的操作
            AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
            if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                // <3.4> 進行過濾,static 修飾的方法不進行注入
                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);
                    }
                }
                // <3.5> 獲取註解中的 `required` 配置
                boolean required = determineRequiredStatus(ann);
                PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                // <3.6> 構建一個 AutowiredMethodElement 物件,新增至 `currElements`
                currElements.add(new AutowiredMethodElement(method, required, pd));
            }
        });

        elements.addAll(0, currElements);
        // <4> 找到父類,迴圈遍歷
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    // <5> 根據從這個 Bean 解析出來的所有 InjectedElement 物件生成一個 InjectionMetadata 注入元資訊物件,並返回
    return new InjectionMetadata(clazz, elements);
}

過程如下:

  1. 建立 currElements 集合,用於儲存 @Autowired@Value 註解標註的欄位
  2. 遍歷這個 Class 物件的所有欄位
    1. 找到該欄位的 @Autowired 或者 @Value 註解,返回 ann 物件,沒有的話返回空物件,則直接跳過不進行下面的操作
    2. 進行過濾,static 修飾的欄位不進行注入
    3. 獲取註解中的 required 配置
    4. 根據該欄位和 required 構建一個 AutowiredFieldElement 物件,新增至 currElements
  3. 遍歷這個 Class 物件的所有方法
    1. 嘗試找到這個方法的橋接方法,沒有的話就是本身這個方法
    2. 如果是橋接方法則直接跳過
    3. 找到該方法的 @Autowired 或者 @Value 註解,返回 ann 物件,沒有的話返回空物件,則直接跳過不進行下面的操作
    4. 進行過濾,static 修飾的方法不進行注入
    5. 獲取註解中的 required 配置
    6. 構建一個 AutowiredMethodElement 物件,新增至 currElements
  4. 找到父類,迴圈遍歷
  5. 根據從這個 Bean 解析出來的所有 InjectedElement 物件生成一個 InjectionMetadata 注入元資訊物件,並返回

整個過程很簡單,就是解析出所有 @Autowired 或者 @Value 註解標註的方法或者欄位,然後構建一個 InjectionMetadata 注入元資訊物件

postProcessProperties 方法

postProcessProperties(PropertyValues pvs, Object bean, String beanName) 方法,根據 @Autowired@Value 註解標註的欄位(或方法)的元資訊進行依賴注入,如下:

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // 找到這個 Bean 的注入元資訊物件
    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;
}

先找到這個 Bean 的注入元資訊物件,上面已經講過了,然後呼叫其 inject(...) 方法,這裡先來看到 InjectionMetadata 這個物件

InjectionMetadata 注入元資訊物件

org.springframework.beans.factory.annotation.InjectionMetadata,某個 Bean 的注入元資訊物件

public class InjectionMetadata {

	private static final Log logger = LogFactory.getLog(InjectionMetadata.class);

	private final Class<?> targetClass;

	/**
	 * 需要注入的欄位(或方法)的元資訊
	 */
	private final Collection<InjectedElement> injectedElements;

	@Nullable
	private volatile Set<InjectedElement> checkedElements;

	public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
		this.targetClass = targetClass;
		this.injectedElements = elements;
	}

	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
				if (logger.isTraceEnabled()) {
					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}
}

可以看到注入方法非常簡單,就是遍歷所有的 InjectedElement 物件,呼叫他們的 inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) 方法

AutowiredFieldElement

AutowiredAnnotationBeanPostProcessor 的私有內部類,注入欄位物件,如下:

private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
    /** 是否必須 */
    private final boolean required;
    /** 是否快取起來了 */
    private volatile boolean cached = false;
    /** 快取的物件 */
    @Nullable
    private volatile Object cachedFieldValue;

    public AutowiredFieldElement(Field field, boolean required) {
        super(field, null);
        this.required = required;
    }

    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        // <1> 獲取 `field` 欄位
        Field field = (Field) this.member;
        Object value;
        // <2> 如果進行快取了,則嘗試從快取中獲取
        if (this.cached) {
            value = resolvedCachedArgument(beanName, this.cachedFieldValue);
        }
        // <3> 否則,開始進行解析
        else {
            // <3.1> 建立一個依賴注入描述器 `desc`
            DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
            desc.setContainingClass(bean.getClass());
            Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
            Assert.state(beanFactory != null, "No BeanFactory available");
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            try {
                /**
                 * <3.2> 通過 {@link org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency} 方法
                 * 找到這個欄位對應的 Bean(們)
                 */
                value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
            }
            catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
            }
            // <3.3> 和快取相關,如果有必要則將本次找到的注入物件快取起來,避免下次再進行解析
            synchronized (this) {
                if (!this.cached) {
                    if (value != null || this.required) {
                        this.cachedFieldValue = desc;
                        registerDependentBeans(beanName, autowiredBeanNames);
                        if (autowiredBeanNames.size() == 1) {
                            String autowiredBeanName = autowiredBeanNames.iterator().next();
                            if (beanFactory.containsBean(autowiredBeanName) &&
                                    beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                        desc, autowiredBeanName, field.getType());
                            }
                        }
                    }
                    else {
                        this.cachedFieldValue = null;
                    }
                    this.cached = true;
                }
            }
        }
        // <4> 如果獲取到該欄位對應的物件,則進行屬性賦值(依賴注入)
        if (value != null) {
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
        }
    }
}

直接看到 inject(...) 方法,注入的過程如下:

  1. 獲取 field 欄位
  2. 如果進行快取了,則嘗試從快取中獲取
  3. 否則,開始進行解析
    1. 建立一個依賴注入描述器 desc
    2. 【核心】通過 DefaultListableBeanFactory#resolveDependency(...) 方法,找到這個欄位對應的 Bean(們)
    3. 和快取相關,如果有必要則將本次找到的注入物件快取起來,避免下次再進行解析
  4. 如果獲取到該欄位對應的物件,則進行屬性賦值(依賴注入),底層就是通過反射機制為該欄位賦值

可以看到整個的核心在於通過 DefaultListableBeanFactory#resolveDependency(...) 方法找到欄位對應的 Bean,這裡也許是一個集合物件,所以也可能找到的是多個 Bean,該方法在後面進行分析

AutowiredMethodElement

AutowiredAnnotationBeanPostProcessor 的私有內部類,注入方法物件,如下:

private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
    /** 是否必須 */
    private final boolean required;
    /** 是否快取起來了 */
    private volatile boolean cached = false;
    /** 快取的方法引數物件 */
    @Nullable
    private volatile Object[] cachedMethodArguments;

    public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
        super(method, pd);
        this.required = required;
    }

    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        if (checkPropertySkipping(pvs)) {
            return;
        }
        // <1> 獲取 `method` 方法
        Method method = (Method) this.member;
        // <2> 如果進行快取了,則嘗試從快取中獲取方法引數物件
        Object[] arguments;
        if (this.cached) {
            // Shortcut for avoiding synchronization...
            arguments = resolveCachedArguments(beanName);
        }
        // <3> 否則,開始進行解析
        else {
            // <3.1> 獲取方法的引數型別集合 `paramTypes`,根據引數位置確定引數
            Class<?>[] paramTypes = method.getParameterTypes();
            arguments = new Object[paramTypes.length];
            // <3.2> 構建一個依賴注入描述器陣列 `descriptors`,用於儲存後續建立的物件
            DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
            Set<String> autowiredBeans = new LinkedHashSet<>(paramTypes.length);
            Assert.state(beanFactory != null, "No BeanFactory available");
            TypeConverter typeConverter = beanFactory.getTypeConverter();
            // <3.3> 根據引數順序遍歷該方法的引數
            for (int i = 0; i < arguments.length; i++) {
                // <3.3.1> 為第 `i` 個方法引數建立一個 MethodParameter 物件
                MethodParameter methodParam = new MethodParameter(method, i);
                // <3.3.2> 建立依賴描述器 `currDesc`,並新增至 `descriptors` 陣列
                DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
                currDesc.setContainingClass(bean.getClass());
                descriptors[i] = currDesc;
                try {
                    /**
                     * <3.3.3> 通過 {@link org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency} 方法
                     * 找到這個方法引數對應的 Bean(們)
                     */
                    Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
                    if (arg == null && !this.required) {
                        arguments = null;
                        break;
                    }
                    arguments[i] = arg;
                }
                catch (BeansException ex) {
                    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
                }
            }
            // <3.4> 和快取相關,如果有必要則將本次找到的方法引數物件快取起來,避免下次再進行解析
            synchronized (this) {
                if (!this.cached) {
                    if (arguments != null) {
                        Object[] cachedMethodArguments = new Object[paramTypes.length];
                        System.arraycopy(descriptors, 0, cachedMethodArguments, 0, arguments.length);
                        registerDependentBeans(beanName, autowiredBeans);
                        if (autowiredBeans.size() == paramTypes.length) {
                            Iterator<String> it = autowiredBeans.iterator();
                            for (int i = 0; i < paramTypes.length; i++) {
                                String autowiredBeanName = it.next();
                                if (beanFactory.containsBean(autowiredBeanName) &&
                                        beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
                                    cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
                                            descriptors[i], autowiredBeanName, paramTypes[i]);
                                }
                            }
                        }
                        this.cachedMethodArguments = cachedMethodArguments;
                    }
                    else {
                        this.cachedMethodArguments = null;
                    }
                    this.cached = true;
                }
            }
        }
        // <4> 如果找到該方法的引數(們),則進行屬性賦值(依賴注入)
        if (arguments != null) {
            try {
                ReflectionUtils.makeAccessible(method);
                // 通過反射機制呼叫該方法
                method.invoke(bean, arguments);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
}

直接看到 inject(...) 方法,注入的過程如下:

  1. 獲取 method 方法
  2. 如果進行快取了,則嘗試從快取中獲取方法引數物件
  3. 否則,開始進行解析
    1. 獲取方法的引數型別集合 paramTypes,根據引數位置確定引數
    2. 構建一個依賴注入描述器陣列 descriptors,用於儲存後續建立的物件
    3. 根據引數順序遍歷該方法的引數
      1. 為第 i 個方法引數建立一個 MethodParameter 物件
      2. 建立依賴描述器 currDesc,並新增至 descriptors 陣列
      3. 【核心】通過 DefaultListableBeanFactory#resolveDependency(...) 方法,找到這個方法引數對應的 Bean(們)
      4. 和快取相關,如果有必要則將本次找到的方法引數物件快取起來,避免下次再進行解析
  4. 如果找到該方法的引數(們),則進行屬性賦值(依賴注入),底層就是通過反射機制呼叫該方法

可以看到整個的核心也是通過 DefaultListableBeanFactory#resolveDependency(...) 方法找到方法引數對應的 Bean,該方法在後面進行分析

CommonAnnotationBeanPostProcessor

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor,主要處理 @Resource 註解進行依賴注入,以及 @PostConstruct@PreDestroy 生命週期註解的處理

體系結構

死磕Spring之IoC篇 - @Autowired 等註解的實現原理

可以看到 CommonAnnotationBeanPostProcessor 實現了 MergedBeanDefinitionPostProcessor 和 InstantiationAwareBeanPostProcessor 兩個介面,還實現了 DestructionAwareBeanPostProcessor 介面,用於生命週期中的初始化和銷燬的處理

構造方法

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
		implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {

	@Nullable
	private static Class<? extends Annotation> webServiceRefClass;

	@Nullable
	private static Class<? extends Annotation> ejbRefClass;

	static {
		try {
			@SuppressWarnings("unchecked")
			Class<? extends Annotation> clazz = (Class<? extends Annotation>)
					ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());
			webServiceRefClass = clazz;
		}
		catch (ClassNotFoundException ex) {
			webServiceRefClass = null;
		}
		try {
			@SuppressWarnings("unchecked")
			Class<? extends Annotation> clazz = (Class<? extends Annotation>)
					ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());
			ejbRefClass = clazz;
		}
		catch (ClassNotFoundException ex) {
			ejbRefClass = null;
		}
	}

	/**
	 * Create a new CommonAnnotationBeanPostProcessor,
	 * with the init and destroy annotation types set to
	 * {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy},
	 * respectively.
	 */
	public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}
}

public class InitDestroyAnnotationBeanPostProcessor
		implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {

	protected transient Log logger = LogFactory.getLog(getClass());

	/**
	 * 初始化註解,預設為 @PostConstruct
	 */
	@Nullable
	private Class<? extends Annotation> initAnnotationType;

	/**
	 * 銷燬註解,預設為 @PreDestroy
	 */
	@Nullable
	private Class<? extends Annotation> destroyAnnotationType;

	private int order = Ordered.LOWEST_PRECEDENCE;

	@Nullable
	private final transient Map<Class<?>, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256);

	public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
		this.initAnnotationType = initAnnotationType;
	}

	public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
		this.destroyAnnotationType = destroyAnnotationType;
	}
}

可以看到會設定初始化註解為 @PostConstruct,銷燬註解為 @PreDestroy,這兩個註解都是 JSR-250 註解;另外如果存在 javax.xml.ws.WebServiceRefjavax.ejb.EJB 註解也是會進行設定的

postProcessMergedBeanDefinition 方法

postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) 方法,找到 @PostConstruct@PreDestroy 註解標註的方法,並構建 LifecycleMetadata 物件,找到 @Resource 註解標註的欄位(或方法)的元資訊,如下:

// CommonAnnotationBeanPostProcessor.java
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 先呼叫父類的方法,找到 @PostConstruct 和 @PreDestroy 註解標註的方法,並構建 LifecycleMetadata 物件
    super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
    // 找到 @Resource 註解標註的欄位(或方法),構建一個 InjectionMetadata 物件,用於後續的屬性注入
    InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

整個的過程原理和 AutowiredAnnotationBeanPostProcessor 差不多,先從快取中獲取,未命中則呼叫對應的方法進行構建,下面先來看看父類中的方法

buildLifecycleMetadata 方法
// InitDestroyAnnotationBeanPostProcessor.java
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
    List<LifecycleElement> initMethods = new ArrayList<>();
    List<LifecycleElement> destroyMethods = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<LifecycleElement> currInitMethods = new ArrayList<>();
        final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                LifecycleElement element = new LifecycleElement(method);
                currInitMethods.add(element);
                if (logger.isTraceEnabled()) {
                    logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
                }
            }
            if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                currDestroyMethods.add(new LifecycleElement(method));
                if (logger.isTraceEnabled()) {
                    logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
                }
            }
        });

        initMethods.addAll(0, currInitMethods);
        destroyMethods.addAll(currDestroyMethods);
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}

整個過程比較簡單,找到這個 Bean 中 @PostConstruct@PreDestroy 註解標註的方法,然後構建一個 LifecycleMetadata 生命週期元資訊物件

buildResourceMetadata 方法
// CommonAnnotationBeanPostProcessor.java
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
                }
                currElements.add(new WebServiceRefElement(field, field, null));
            }
            else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@EJB annotation is not supported on static fields");
                }
                currElements.add(new EjbRefElement(field, field, null));
            }
            else if (field.isAnnotationPresent(Resource.class)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@Resource annotation is not supported on static fields");
                }
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    currElements.add(new ResourceElement(field, field, null));
                }
            }
        });

        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
                    }
                    if (method.getParameterCount() != 1) {
                        throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
                    }
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
                }
                else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@EJB annotation is not supported on static methods");
                    }
                    if (method.getParameterCount() != 1) {
                        throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
                    }
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new EjbRefElement(method, bridgedMethod, pd));
                }
                else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@Resource annotation is not supported on static methods");
                    }
                    Class<?>[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length != 1) {
                        throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
                    }
                    if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new ResourceElement(method, bridgedMethod, pd));
                    }
                }
            }
        });

        elements.addAll(0, currElements);
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return new InjectionMetadata(clazz, elements);
}

整個過程也比較簡單,解析出這個 Bean 帶有 @Resource 註解的所有欄位(或方法),構建成對應的 ResourceElement 物件,然後再構建成一個 InjectionMetadata 注入元資訊物件

postProcessProperties 方法

postProcessProperties(PropertyValues pvs, Object bean, String beanName) 方法,根據 @Resource 註解標註的欄位(或方法)的元資訊進行依賴注入,如下:

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

先找到這個 Bean 的注入元資訊物件,上面已經講過了,然後呼叫其 inject(...) 方法,該物件上面已經講過了,實際就是呼叫其內部 InjectedElement 的 inject(...) 方法

postProcessBeforeInitialization 方法

初始化 Bean 的時候會先執行 @PostConstruct 標註的初始化方法

// InitDestroyAnnotationBeanPostProcessor.java
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 找到 @PostConstruct 和 @PreDestroy 註解標註的方法們所對應的 LifecycleMetadata 物件
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // 執行 @PostConstruct 標註的初始化方法
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}
// InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata
public void invokeInitMethods(Object target, String beanName) throws Throwable {
    Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
    Collection<LifecycleElement> initMethodsToIterate =
            (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
    if (!initMethodsToIterate.isEmpty()) {
        for (LifecycleElement element : initMethodsToIterate) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
            }
            element.invoke(target);
        }
    }
}

postProcessBeforeDestruction 方法

銷燬 Bean 的時候先執行 @PreDestroy 註解標註的銷燬方法

// InitDestroyAnnotationBeanPostProcessor.java
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
    // 找到 @PostConstruct 和 @PreDestroy 註解標註的方法們所對應的 LifecycleMetadata 物件
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // 執行 @PreDestroy 標註的銷燬方法
        metadata.invokeDestroyMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";
        if (logger.isDebugEnabled()) {
            logger.warn(msg, ex.getTargetException());
        }
        else {
            logger.warn(msg + ": " + ex.getTargetException());
        }
    }
    catch (Throwable ex) {
        logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
    }
}
// InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata
public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
    Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods;
    Collection<LifecycleElement> destroyMethodsToUse =
            (checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
    if (!destroyMethodsToUse.isEmpty()) {
        for (LifecycleElement element : destroyMethodsToUse) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking destroy method on bean '" + beanName + "': " + element.getMethod());
            }
            element.invoke(target);
        }
    }
}

ResourceElement

CommonAnnotationBeanPostProcessor 的私有內部類,@Resource 注入欄位(或方法)物件

構造方法

protected abstract class LookupElement extends InjectionMetadata.InjectedElement {

    /** Bean 的名稱 */
    protected String name = "";
	/** 是否為預設的名稱(通過註解定義的) */
    protected boolean isDefaultName = false;
	/** Bean 的型別 */
    protected Class<?> lookupType = Object.class;

    @Nullable
    protected String mappedName;

    public LookupElement(Member member, @Nullable PropertyDescriptor pd) {
        super(member, pd);
    }
    
    public final DependencyDescriptor getDependencyDescriptor() {
        if (this.isField) {
            return new LookupDependencyDescriptor((Field) this.member, this.lookupType);
        }
        else {
            return new LookupDependencyDescriptor((Method) this.member, this.lookupType);
        }
    }
}

private class ResourceElement extends LookupElement {
	/** 是否延遲載入 */
    private final boolean lazyLookup;

    public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
        super(member, pd);
        Resource resource = ae.getAnnotation(Resource.class);
        String resourceName = resource.name();
        Class<?> resourceType = resource.type();
        this.isDefaultName = !StringUtils.hasLength(resourceName);
        if (this.isDefaultName) {
            resourceName = this.member.getName();
            if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
                resourceName = Introspector.decapitalize(resourceName.substring(3));
            }
        }
        else if (embeddedValueResolver != null) {
            resourceName = embeddedValueResolver.resolveStringValue(resourceName);
        }
        if (Object.class != resourceType) {
            checkResourceType(resourceType);
        }
        else {
            // No resource type specified... check field/method.
            resourceType = getResourceType();
        }
        this.name = (resourceName != null ? resourceName : "");
        this.lookupType = resourceType;
        String lookupValue = resource.lookup();
        this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
        Lazy lazy = ae.getAnnotation(Lazy.class);
        this.lazyLookup = (lazy != null && lazy.value());
    }
}

ResourceElement 的構造方法會通過 @Resource 註解和該欄位(或方法)解析出基本資訊

可以看到還繼承了 InjectionMetadata 的靜態內部類 InjectedElement,我們先來看到這個類的 inject(...) 方法

inject 方法

public abstract static class InjectedElement {

    protected final Member member;

    protected final boolean isField;

    protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
            throws Throwable {
        if (this.isField) {
            Field field = (Field) this.member;
            ReflectionUtils.makeAccessible(field);
            field.set(target, getResourceToInject(target, requestingBeanName));
        } else {
            if (checkPropertySkipping(pvs)) {
                return;
            }
            try {
                Method method = (Method) this.member;
                ReflectionUtils.makeAccessible(method);
                method.invoke(target, getResourceToInject(target, requestingBeanName));
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
    
    @Nullable
	protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
		return null;
	}
}

不管是欄位還是方法,底層都是通過反射機制進行賦值或者呼叫,都會呼叫 getResourceToInject(...) 方法獲取到欄位值或者方法引數

getResourceToInject 方法

@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
    return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
            getResource(this, requestingBeanName));
}

如果是延遲載入,則呼叫 buildLazyResourceProxy(...) 方法返回一個代理物件,如下:

protected Object buildLazyResourceProxy(final LookupElement element, final @Nullable String requestingBeanName) {
    TargetSource ts = new TargetSource() {
        @Override
        public Class<?> getTargetClass() {
            return element.lookupType;
        }
        @Override
        public boolean isStatic() {
            return false;
        }
        @Override
        public Object getTarget() {
            return getResource(element, requestingBeanName);
        }
        @Override
        public void releaseTarget(Object target) {
        }
    };
    ProxyFactory pf = new ProxyFactory();
    pf.setTargetSource(ts);
    if (element.lookupType.isInterface()) {
        pf.addInterface(element.lookupType);
    }
    ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
            ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null);
    return pf.getProxy(classLoader);
}

否則,呼叫 getResource(...) 方法獲取注入物件

getResource 方法

protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
        throws NoSuchBeanDefinitionException {

    if (StringUtils.hasLength(element.mappedName)) {
        return this.jndiFactory.getBean(element.mappedName, element.lookupType);
    }
    if (this.alwaysUseJndiLookup) {
        return this.jndiFactory.getBean(element.name, element.lookupType);
    }
    if (this.resourceFactory == null) {
        throw new NoSuchBeanDefinitionException(element.lookupType,
                "No resource factory configured - specify the 'resourceFactory' property");
    }
    return autowireResource(this.resourceFactory, element, requestingBeanName);
}

前面的判斷忽略掉,直接看到最後會呼叫 autowireResource(...) 方法,並返回注入資訊

autowireResource 方法

protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
        throws NoSuchBeanDefinitionException {

    Object resource;
    Set<String> autowiredBeanNames;
    String name = element.name;

    if (factory instanceof AutowireCapableBeanFactory) {
        AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
        DependencyDescriptor descriptor = element.getDependencyDescriptor();
        if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
            autowiredBeanNames = new LinkedHashSet<>();
            resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
            if (resource == null) {
                throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
            }
        }
        else {
            resource = beanFactory.resolveBeanByName(name, descriptor);
            autowiredBeanNames = Collections.singleton(name);
        }
    }
    else {
        resource = factory.getBean(name, element.lookupType);
        autowiredBeanNames = Collections.singleton(name);
    }

    if (factory instanceof ConfigurableBeanFactory) {
        ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
        for (String autowiredBeanName : autowiredBeanNames) {
            if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
                beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
            }
        }
    }

    return resource;
}

@Resource 註解相比於 @Autowired 註解的處理更加複雜點,不過我們這裡可以看到也會呼叫 DefaultListableBeanFactory#resolveDependency(...) 方法,找到對應的注入物件,該方法在後面進行分析

1. resolveDependency 處理依賴方法

resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) 方法,找到對應的依賴 Bean,該方法在《Bean 的建立過程》中也提到了,獲取 Bean 的例項物件時,構造器注入的引數也是通過該方法獲取的,本文的依賴注入底層也是通過該方法實現的,這裡我們對該方法一探究竟

// DefaultListableBeanFactory.java
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    // <1> 設定引數名稱探測器,例如通過它獲取方法引數的名稱
    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    // <2> 如果依賴型別為 Optional 型別
    if (Optional.class == descriptor.getDependencyType()) {
        // 呼叫 `createOptionalDependency(...)` 方法,先將 `descriptor` 注入表述器封裝成 NestedDependencyDescriptor 物件
        // 底層處理和下面的 `5.2` 相同
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    // <3> 否則,如果依賴型別為 ObjectFactory 或 ObjectProvider 型別
    else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) {
        // 返回一個 DependencyObjectProvider 私有內部類物件,並沒有獲取到例項的 Bean,需要呼叫其 getObject() 方法獲取目標物件
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    // <4> 否則,如果依賴型別為 javax.inject.Provider 型別
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        // 返回一個 Jsr330Provider 私有內部類物件,該物件也繼承 DependencyObjectProvider
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    // <5> 否則,通用的處理邏輯
    else {
        // <5.1> 先通過 AutowireCandidateResolver 嘗試獲取一個代理物件,延遲依賴注入則會返回一個代理物件
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
        // <5.2> 如果上面沒有返回代理物件,則進行處理,呼叫 `doResolveDependency(...)` 方法
        if (result == null) {
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
}

過程如下:

  1. 設定引數名稱探測器,例如通過它獲取方法引數的名稱
  2. 如果依賴型別為 Optional 型別,則呼叫 createOptionalDependency(...) 方法,先將 descriptor 注入表述器封裝成 NestedDependencyDescriptor 物件,底層處理和下面的 5.2 相同
  3. 否則,如果依賴型別為 ObjectFactory 或 ObjectProvider 型別,直接返回一個 DependencyObjectProvider 私有內部類物件,並沒有獲取到例項的 Bean,需要呼叫其 getObject() 方法獲取目標物件
  4. 否則,如果依賴型別為 javax.inject.Provider 型別,直接返回一個 Jsr330Provider 私有內部類物件,該物件也繼承 DependencyObjectProvider
  5. 否則,通用的處理邏輯
    1. 先通過 AutowireCandidateResolver 嘗試獲取一個代理物件,延遲依賴注入則會返回一個代理物件
    2. 如果上面沒有返回代理物件,則進行處理,呼叫 doResolveDependency(...) 方法

我們需要關注的是上面的第 5.2 步所呼叫 doResolveDependency(...) 方法,這一步是底層實現

2. doResolveDependency 底層處理依賴方法

// DefaultListableBeanFactory.java
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    // 設定當前執行緒的注入點,並返回上次的注入點,屬於巢狀注入的一個保護點
    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        // <1> 針對給定的工廠給定一個快捷實現的方式,暫時忽略
        // 例如考慮一些預先解析的資訊,在進入所有 Bean 的常規型別匹配演算法之前,解析演算法將首先嚐試通過此方法解析快捷方式
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            // 返回快捷的解析資訊
            return shortcut;
        }

        // 依賴的型別
        Class<?> type = descriptor.getDependencyType();
        // <2> 獲取註解中的 value 對應的值,例如 @Value、@Qualifier 註解配置的 value 屬性值,注意 @Autowired 沒有 value 屬性配置
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                // <2.1> 解析註解中的 value,因為可能是佔位符,需要獲取到相應的資料
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                        getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            try {
                // <2.2> 進行型別轉換,並返回
                return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
            }
            catch (UnsupportedOperationException ex) {
                // A custom TypeConverter which does not support TypeDescriptor resolution...
                return (descriptor.getField() != null ?
                        converter.convertIfNecessary(value, type, descriptor.getField()) :
                        converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
            }
        }

        // <3> 解析複合的依賴物件(Array、Collection、Map 型別),獲取該屬性元素型別的 Bean 們
        // 底層和第 `4` 原理一樣,這裡會將 `descriptor` 封裝成 MultiElementDescriptor 型別
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }

        // <4> 查詢與型別相匹配的 Bean 們
        // 返回結果:key -> beanName;value -> 對應的 Bean
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        // <5> 如果一個都沒找到
        if (matchingBeans.isEmpty()) {
            // <5.1> 如果 @Autowired 配置的 required 為 true,表示必須,則丟擲異常
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            // <5.2> 否則,返回一個空物件
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;

        // <6> 如果匹配的 Bean 有多個,則需要找出最優先的那個
        if (matchingBeans.size() > 1) {
            // <6.1> 找到最匹配的那個 Bean,通過 @Primary 或者 @Priority 來決定,或者通過名稱決定
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    // <6.2> 如果沒有找到最匹配的 Bean,則丟擲 NoUniqueBeanDefinitionException 異常
                    return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                }
                else {
                    // In case of an optional Collection/Map, silently ignore a non-unique case:
                    // possibly it was meant to be an empty collection of multiple regular beans
                    // (before 4.3 in particular when we didn't even look for collection beans).
                    return null;
                }
            }
            // <6.3> 獲取到最匹配的 Bean,傳值引用給 `instanceCandidate`
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        // <7> 否則,只有一個 Bean,則直接使用其作為最匹配的 Bean
        else {
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        // <8> 將依賴注入的 Bean 的名稱新增至方法入參 `autowiredBeanNames` 集合,裡面儲存依賴注入的 beanName
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        // <9> 如果匹配的 Bean 是 Class 物件,則根據其 beanName 依賴查詢到對應的 Bean
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        if (result instanceof NullBean) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            result = null;
        }
        if (!ClassUtils.isAssignableValue(type, result)) {
            throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
        }
        // <10> 返回依賴注入的 Bean
        return result;
    }
    finally {
        // 設定當前執行緒的注入點為上一次的注入點,因為本次注入結束了
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

依賴處理的過程稍微有點複雜,如下:

  1. 針對給定的工廠給定一個快捷實現的方式,暫時忽略

    例如考慮一些預先解析的資訊,在進入所有 Bean 的常規型別匹配演算法之前,解析演算法將首先嚐試通過此方法解析快捷方式

  2. 獲取註解中的 value 對應的值,例如 @Value@Qualifier 註解配置的 value 屬性值,注意 @Autowired 沒有 value 屬性配置

    1. 解析註解中的 value,因為可能是佔位符,需要獲取到相應的資料
    2. 進行型別轉換,並返回
  3. 解析複合的依賴物件(Array、Collection、Map 型別),獲取該屬性元素型別的 Bean 們,呼叫 resolveMultipleBeans(...) 方法

    底層和下面第 4 步原理一樣,這裡會將 descriptor 封裝成 MultiElementDescriptor 型別,如果找到了則直接返回

  4. 查詢與型別相匹配的 Bean 們,呼叫 findAutowireCandidates(...) 方法

    返回結果:key -> beanName;value -> 對應的 Bean

  5. 如果一個都沒找到

    1. 如果 @Autowired 配置的 required 為 true,表示必須,則丟擲異常
    2. 否則,返回一個空物件
  6. 如果匹配的 Bean 有多個,則需要找出最優先的那個

    1. 找到最匹配的那個 Bean,通過 @Primary 或者 @Priority 來決定,或者通過名稱決定,呼叫determineAutowireCandidate(...) 方法
    2. 如果沒有找到最匹配的 Bean,則丟擲 NoUniqueBeanDefinitionException 異常
    3. 獲取到最匹配的 Bean,傳值引用給 instanceCandidate
  7. 否則,只有一個 Bean,則直接使用其作為最匹配的 Bean

  8. 將依賴注入的 Bean 的名稱新增至方法入參 autowiredBeanNames 集合,裡面儲存依賴注入的 beanName

  9. 如果匹配的 Bean 是 Class 物件,則根據其 beanName 依賴查詢到對應的 Bean

  10. 返回依賴注入的 Bean

關於上面第 3 步對於符合依賴物件的處理這裡不做詳細分析,因為底層和第 4 步一樣,接下來分析上面第 46 步所呼叫的方法

findAutowireCandidates 方法

findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) 方法,找到符合條件的依賴注入的 Bean 們,如下:

// DefaultListableBeanFactory.java
protected Map<String, Object> findAutowireCandidates(
        @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

    // <1> 從當前上下文找到該型別的 Bean 們(根據型別)
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this, requiredType, true, descriptor.isEager());
    // <2> 定義一個 Map 物件 `result`,用於儲存符合條件的 Bean
    Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
    /**
     * <3> 遍歷 Spring 內部已處理的依賴物件集合,可以跳到 AbstractApplicationContext#prepareBeanFactory 方法中看看
     * 會有一下幾個內建處理物件:
     * BeanFactory 型別 -> 返回 DefaultListableBeanFactory
     * ResourceLoader、ApplicationEventPublisher、ApplicationContext 型別 ->  返回 ApplicationContext 物件
     */
    for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
        Class<?> autowiringType = classObjectEntry.getKey();
        if (autowiringType.isAssignableFrom(requiredType)) {
            Object autowiringValue = classObjectEntry.getValue();
            autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
            if (requiredType.isInstance(autowiringValue)) {
                result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                break;
            }
        }
    }

    // <4> 遍歷第 `1` 步找到的 Bean 的名稱們
    for (String candidate : candidateNames) {
        // <4.1> 如果滿足下面兩個條件,則新增至 `result` 集合中
        if (!isSelfReference(beanName, candidate) // 如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)
                && isAutowireCandidate(candidate, descriptor)) { // 符合注入的條件
            addCandidateEntry(result, candidate, descriptor, requiredType);
        }
    }
    // <5> 如果沒有找到符合條件的 Bean,則再嘗試獲取
    if (result.isEmpty()) {
        boolean multiple = indicatesMultipleBeans(requiredType);
        // Consider fallback matches if the first pass failed to find anything...
        DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
        // <5.1> 再次遍歷第 `1` 步找到的 Bean 的名稱們
        for (String candidate : candidateNames) {
            // <5.2> 如果滿足下面三個條件,則新增至 `result` 集合中
            if (!isSelfReference(beanName, candidate) // 如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)
                    && isAutowireCandidate(candidate, fallbackDescriptor) // 符合注入的條件
                    && (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) { // 不是複合型別,或者有 @Qualifier 註解
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        // <6> 如果還沒有找到符合條件的 Bean,則再嘗試獲取
        // 和上面第 `5` 步的區別在於必須是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)
        if (result.isEmpty() && !multiple) {
            // Consider self references as a final pass...
            // but in the case of a dependency collection, not the very same bean itself.
            for (String candidate : candidateNames) {
                if (isSelfReference(beanName, candidate)
                        && (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate))
                        && isAutowireCandidate(candidate, fallbackDescriptor)) {
                    addCandidateEntry(result, candidate, descriptor, requiredType);
                }
            }
        }
    }
    // <7> 返回 `result`,符合條件的 Bean
    return result;
}

過程大致如下:

  1. 從當前上下文找到該型別的 Bean 們(根據型別

  2. 定義一個 Map 物件 result,用於儲存符合條件的 Bean

  3. 遍歷 Spring 內部已處理的依賴物件集合,例如你依賴注入 BeanFactory 型別的物件,則拿到的是 DefaultListableBeanFactory 物件,依賴注入 ResourceLoader、ApplicationEventPublisher、ApplicationContext 型別的物件, 拿到的就是當前 Spring 上下文 ApplicationContext 物件

  4. 遍歷第 1 步找到的 Bean 的名稱們

    1. 如果滿足下面兩個條件,則新增至 result 集合中

      如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)、符合注入的條件

  5. 如果沒有找到符合條件的 Bean,則再嘗試獲取

    1. 再次遍歷第 1 步找到的 Bean 的名稱們

    2. 如果滿足下面三個條件,則新增至 result 集合中

      如果不是自引用(這個 Bean 不是在需要依賴它的 Bean 的內部定義的)、符合注入的條件、不是複合型別,或者有 @Qualifier 註解

  6. 如果還沒有找到符合條件的 Bean,則再嘗試獲取,和上面第 5 步的區別在於必須是自引用(這個 Bean 是在需要依賴它的 Bean 的內部定義的)

  7. 返回 result,符合條件的 Bean

總結下來:從當前上下文找到所有該型別的依賴注入物件然後返回,注意,如果你依賴注入的物件就是本身這個 Bean 內部定義的物件有特殊處理。

例如注入一個集合物件,元素型別的 Bean 有一個是定義在本身這個 Bean 的內部,如果僅有這個 Bean 則會注入進行;如果除了本身這個 Bean 內部定義了,其他地方也定義了,那麼本身這個 Bean 內部定義的 Bean 是不會被注入的;因為是自引用的 Bean 不會優先考慮,除非一個都沒找到,才會嘗試獲取自引用的 Bean

determineAutowireCandidate 方法

determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) 方法,找到最匹配的那個依賴注入物件,如下:

@Nullable
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    // <1> 嘗試獲取一個 @Primary 註解標註的 Bean,如果有找到多個則會丟擲異常
    String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
    // <2> 如果第 `1` 步找到了則直接返回
    if (primaryCandidate != null) {
        return primaryCandidate;
    }
    // <3> 嘗試找到 @Priority 註解優先順序最高的那個 Bean,如果存在相同的優先順序則會丟擲異常
    String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
    // <4> 如果第 `3` 步找到了則直接返回
    if (priorityCandidate != null) {
        return priorityCandidate;
    }
    // Fallback
    // <5> 兜底方法,遍歷所有的 Bean
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateName = entry.getKey();
        Object beanInstance = entry.getValue();
        // <5.1> 如果滿足下面其中一個條件則直接返回
        if ((beanInstance != null 
            && this.resolvableDependencies.containsValue(beanInstance)) // 該 Bean 為 Spring 內部可處理的 Bean,例如 ApplicationContext
            || matchesBeanName(candidateName, descriptor.getDependencyName())) { // 名稱相匹配
            return candidateName;
        }
    }
    // <6> 上面都沒選出來則返回一個空物件
    return null;
}

如果找到了多個匹配的依賴注入物件,則需要找到最匹配的那個 Bean,過程大致如下:

  1. 嘗試獲取一個 @Primary 註解標註的 Bean,如果有找到多個則會丟擲異常
  2. 如果第 1 步找到了則直接返回
  3. 嘗試找到 @Priority 註解優先順序最高的那個 Bean,如果存在相同的優先順序則會丟擲異常
  4. 如果第 3 步找到了則直接返回
  5. 兜底方法,遍歷所有的 Bean
    1. 如果滿足下面其中一個條件則直接返回:該 Bean 為 Spring 內部可處理的 Bean(例如 ApplicationContext、BeanFactory)、名稱相匹配
  6. 上面都沒選出來則返回一個空物件

總結

本文講述了 @Autowired@Value@Resource 等註解的實現原理,在《Bean 的建立過程》中我們可以瞭解到,在 Spring Bean 生命週期的很多階段都可以通過相應的 BeanPostProcessor 處理器進行擴充套件,其中《Bean 的屬性填充階段》會通過 InstantiationAwareBeanPostProcessor 對 Bean 進行處理,有以下兩個處理器:

  • AutowiredAnnotationBeanPostProcessor,主要處理 @Autowired@Value 註解進行依賴注入
  • CommonAnnotationBeanPostProcessor,主要處理 @Resource 註解進行依賴注入,以及 @PostConstruct@PreDestroy 生命週期註解的處理

原理就是找到註解標註的欄位(或方法),建立對應的注入元資訊物件,然後根據該元資訊物件進行注入(反射機制),底層都是通過 DefaultListableBeanFactory#resolveDependency 方法實現的,找到符合條件的 Bean(根據型別),然後篩選出最匹配的那個依賴注入物件。

疑問:@Bean 等註解的實現原理又是怎樣的呢?別急,在後續文章進行分析

相關文章