likes
comments
collection
share

SpringIOC之依赖自动注入六层筛选源码剖析

作者站长头像
站长
· 阅读数 18

Spring IOC 中的依赖自动注入功能是通过 BeanFactory 的 AutowireCapableBeanFactory 接口实现的。当 Spring IOC 容器在创建 Bean 的时候,会检查 Bean 中的依赖属性,如果这些属性没有被赋值,那么 Spring 会尝试自动注入这些属性。 这些规则包括以下六个层次:

  1. Spring 会根据类型来确定要注入的 Bean 实例。如果存在多个符合类型的 Bean 实例,会抛出 NoUniqueBeanDefinitionException 异常,提示存在多个相同类型的 Bean。
  2. 如果存在多个符合类型的 Bean 实例,但是其中有一个 Bean 实例被标记为 @Primary,那么 Spring 会选择被标记为 @Primary 的 Bean 实例。
  3. 如果存在多个符合类型的 Bean 实例,但是其中有一个 Bean 实例被标记为 @Qualifier,那么 Spring 会选择被标记为 @Qualifier 的 Bean 实例。
  4. 如果存在多个符合类型的 Bean 实例,但是其中只有一个 Bean 实例的名称与属性名称匹配,那么 Spring 会选择这个 Bean 实例。
  5. 如果存在多个符合类型的 Bean 实例,但是其中只有一个 Bean 实例的名称与属性名称不匹配,那么 Spring 会尝试使用属性名称的驼峰式大小写规则来匹配 Bean 实例的名称,如果匹配成功,那么 Spring 会选择这个 Bean 实例。
  6. 如果以上五个层次都无法选择要注入的 Bean 实例,那么 Spring 会抛出 NoSuchBeanDefinitionException 异常,提示找不到符合条件的 Bean 自动注入依赖的源码剖析:

Spring IOC 会调用 BeanFactory 的 getBean() 方法来获取要注入的 Bean 实例。在获取 Bean 实例时,Spring 会根据属性的类型或名称来查找符合条件的 Bean 实例,如果存在多个符合条件的 Bean 实例,那么 Spring 会根据上述六个层次的规则来选择要注入的 Bean 实例。 在选择要注入的 Bean 实例时,Spring 会调用 AutowiredAnnotationBeanPostProcessor 类的 getInjectedObject() 方法来进行依赖注入。在这个方法中,Spring 会调用 BeanFactory 的 resolveDependency() 方法来获取要注入的依赖项。 在 resolveDependency() 方法中,Spring 会根据要注入的依赖项的类型、名称、注解等信息来查找符合条件的 Bean 实例。如果存在多个符合条件的 Bean 实例,那么 Spring 会根据上述六个层次的规则来选择要注入的 Bean 实例。 最终,Spring 会将选择的 Bean 实例注入到目标对象中的依赖属性中,完成依赖注入的过程。

Spring IOC 自动注入依赖的六层筛选是通过 BeanFactory 的 getBean() 方法和 AutowiredAnnotationBeanPostProcessor 类的 getInjectedObject() 方法来实现的。在选择要注入的 Bean 实例时,Spring 会根据类型、名称、注解等信息来查找符合条件的 Bean 实例,并根据上述六个层次的规则来进行选择。

我们通过源码分析一下,每一层筛选是如何实现的,并给出相应的源码分析。

spring IOC bean注入源码分析

  1. 通过类型匹配查找候选 Bean

这一步是通过类型来查找所有可能的候选 Bean,Spring 会从容器中查找所有与依赖类型兼容(包括实现了接口和继承了父类)的 Bean 实例,并将这些 Bean 实例保存在一个候选列表中。

protected <T> Map<String, T> findAutowireCandidates(
    String beanName, Class<T> requiredType, DependencyDescriptor descriptor) {
// 从容器中查找所有与依赖类型兼容的 Bean 实例
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
        this.beanFactory, requiredType, true, descriptor.isEager());
Map<String, T> result = new LinkedHashMap<>(candidateNames.length);
for (String candidateName : candidateNames) {
    // 只添加非抽象、非懒加载的 Bean 实例
    if (!candidateName.equals(beanName) && !containsBeanDefinition(candidateName)) {
        result.put(candidateName, getBean(candidateName, requiredType));
    }
}
return result;

}

2. 通过名称匹配查找候选 Bean

如果第一步找到的候选 Bean 不止一个,那么 Spring 会继续通过名称来匹配 Bean,如果依赖属性的名称与 Bean 的名称匹配,那么 Spring 会优先选择这个 Bean。

protected Object autowireByName(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
    // 查找与属性名称匹配的 Bean
    if (containsBean(propertyName)) {
        Object bean = getBean(propertyName);
        // 注入依赖属性
        pvs.add(propertyName, bean);
        registerDependentBean(propertyName, beanName);
        if (logger.isTraceEnabled()) {
            logger.trace("Autowiring by name from bean name '{}' via property '{}' to bean named '{}'",
                    beanName, propertyName, propertyName);
        }
    }
}
return null;
}

3. 通过主要标识查找 Bean

如果第二步找到的候选 Bean 不止一个,那么 Spring 会继续查找主要标识的 Bean,主要标识是在 Bean 定义中通过 @Primary 注解指定的 Bean。

protected Object autowireByType(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, TypeConverter converter) {
Object value = null;
Class<?> type = bw.getWrappedClass();
// 按类型查找所有候选 Bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, mbd);
if (!matchingBeans.isEmpty()) {
    // 查找主要标识的 Bean
    String primaryBeanName = determinePrimaryCandidate(matchingBeans, type);
    if (primaryBeanName != null) {
        Object primaryBean = matchingBeans.get(primaryBeanName);
        // 注入依赖属性
        value = primaryBean;
        bw.setPropertyValue(new PropertyValue(propertyDescriptor.getName(), value));
    }
}
return value;
}

4. 通过限定符查找

如果前面的步骤还没有找到合适的 Bean,那么 Spring 会检查依赖属性上是否有限定符(@Qualifier 注解),如果有,那么 Spring 会根据限定符来选择对应的 Bean。

protected Object resolveQualifier(
    String beanName, AbstractBeanDefinition mbd, String typeBeanName) {
Object value = null;
// 查找 BeanFactory 中所有匹配的 Bean
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
        this.beanFactory, this.descriptor.getResolvableType().getType(), true, false);
for (String candidateName : candidateNames) {
    if (candidateName.equals(beanName)) {
        continue;
    }
    if (this.beanFactory instanceof
    
    

5. 通过构造函数查找

如果前面的步骤还没有找到合适的 Bean,那么 Spring 会尝试通过构造函数来注入依赖。Spring IOC 会检查 Bean 中的构造函数,然后查找所有参数类型与依赖属性类型匹配的 Bean,如果有且仅有一个 Bean 与之匹配,那么 Spring 会使用该 Bean 来注入依赖属性。

protected Object autowireConstructor(
    String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors,
    Object[] explicitArgs) {

if (chosenCtors == null) {
    // 选择最匹配的构造函数
    chosenCtors = determineConstructorsFromBeanPostProcessors(mbd.getBeanClass(), beanName);
    if (chosenCtors == null) {
        // 没有找到匹配的构造函数
        throw new UnsatisfiedDependencyException(
                getResourceDescription(), beanName, "No suitable constructor found", null);
    }
}

Constructor<?> constructorToUse = null;
Object[] argsToUse = null;
int minNrOfArgsResolved = Integer.MAX_VALUE;
Map<String, Object> candidateBeans = findAutowireCandidates(beanName, Object.class, new LinkedMultiValueMap<>());

for (Constructor<?> ctor : chosenCtors) {
    Class<?>[] paramTypes = ctor.getParameterTypes();
    // 检查构造函数参数类型是否与依赖属性类型匹配
    if (constructorToUse != null || paramTypes.length != explicitArgs.length) {
        continue;
    }

    Object[] args = new Object[paramTypes.length];
    int nrOfArgsResolved = 0;
    for (int i = 0; i < args.length; i++) {
        Class<?> paramType = paramTypes[i];
        Object autowiredArgument = null;
        String autowiredBeanName = null;
        if (explicitArgs != null && i < explicitArgs.length) {
            // 如果指定了构造函数参数,则使用指定的参数
            autowiredArgument = explicitArgs[i];
        } else {
            // 如果没有指定构造函数参数,则从 BeanFactory 中查找匹配的 Bean
            DependencyDescriptor desc = new DependencyDescriptor(new MethodParameter(ctor, i), true);
            desc.setContainingClass(mbd.getBeanClass());
            Object[] argsToResolve = new Object[]{desc};
            try {
                autowiredArgument = this.beanFactory.resolveDependency(desc, beanName, candidateBeans, this.typeConverter);
            } catch (NoUniqueBeanDefinitionException ex) {
                throw ex;
            } catch (NoSuchBeanDefinitionException ex) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Ignoring NoSuchBeanDefinitionException for optional dependency on constructor: " + ex);
                }
            }
        }
        if (autowiredArgument != null) {
            nrOfArgsResolved++;
            args[i] = autowiredArgument;
        }
    }
    if (nrOfArgsResolved < minNrOfArgsResolved) {
        // 选择参数最少的构造函数
        constructorToUse = ctor;
        argsToUse = args;
        minNrOfArgsResolved = nrOfArgsResolved;
    }
}

if (constructorToUse == null) {
    // 没有找到匹配的构造函数
    throw new UnsatisfiedDependencyException(
            getResourceDescription(), beanName, "No suitable constructor found", null);
}

return this.beanFactory.instantiateBean(beanName, mbd, constructorToUse, argsToUse);
}

Spring IOC 容器通过构造函数查找 Bean 的实现方法。Spring 先通过 determineConstructorsFromBeanPostProcessors 方法选择最匹配的构造函数,然后使用 findAutowireCandidates 方法查找所有参数类型与依赖属性类型匹配的 Bean,最后返回使用该构造函数实例化的 Bean。如果没有找到匹配的构造函数或 Bean,那么 Spring 会抛出 UnsatisfiedDependencyException 异常。