Spring IOC - Bean的生命周期之依赖注入

在Spring启动流程中,创建的factoryBean是DefaultListableBeanFactory,其类图如下所示:

可以看到其直接父类是AbstractAutoireCapableBeanFactory,他主要负责完成Bean的自动装配和创建工作。 具体来说,AbstractAutowireCapableBeanFactory会完成以下工作:

  1. 根据Bean的定义信息创建Bean实例;
  2. 根据Bean的定义信息完成Bean的依赖注入;
  3. 根据Bean的定义信息完成Bean的初始化工作;
  4. 返回创建好的Bean实例。

其中,属性注入是AbstractAutowireCapableBeanFactory的核心功能之一。它会根据Bean的定义信息,自动将依赖的Bean注入到当前Bean中。具体来说,它会根据Bean的依赖关系,自动查找并创建依赖的Bean实例,并将其注入到当前Bean中。

除了属性注入,AbstractAutowireCapableBeanFactory还支持构造函数注入、工厂方法注入等多种注入方式,可以满足不同场景下的需求。

其核心方法AbstractAutowireCapableBeanFactory#populateBean,下面,我们看一下populateBean方法是怎么进行依赖注入的。它处理Spring的各种依赖注入:包括自动注入(名称注入和类型注入)、注解注入(@Autowired和@Value等)、手动注入等。

  1. 首先,判断是否需要进行属性注入。调用 ibp#postProcessAfterInstantiation

  2. 自动注入 :包括名称注入和类型注入。不推荐使用,只支持 XML 配置方式。

  3. 注解注入:处理 @Autowired 和 @Value 等注解,Spring 提供 ibp#postProcessProperties 可以调整 bean 实例。如 AutowiredAnnotationBeanPostProcessor 用于处理 @Autowired 和 @Value 注解。CommonAnnotationBeanPostProcessor 用于处理 @Resource 注解。

  4. 依赖检查:检查要注入的依赖是否已经完整。可以只检查简单类型(Java 原生类型、Enum、Class 等),也可以只检查对象类型。

  5. 手动注入:最基础的注入方式,实际上都委托给了 BeanWrapper 处理。

java 复制代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 1. 判断是否需要进行属性注入:ibp#postProcessAfterInstantiation
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }

    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    // 2. 自动注入:包括名称注入和类型注入
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // 2.1 自动根据名称注入
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // 2.2 自动根据类型注入
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    // 3. 注解注入:后置处理器ibp#postProcessProperties,大名鼎鼎的@Autowired就是在这处理的。
    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;
            }
        }
    }
    // 4. 依赖检查,循环依赖...
    if (needsDepCheck) {
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    // 5. 手动依赖注入
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

这里重点讲解AutowiredAnnotationBeanPostProcessor为代表的注解注入方式。其会调用到Spring进行依赖查找的核心API: beanFactory#resolveDependency,其本质是根据类型查找依赖,调用beanFactory#beanNamesForType方法根据类型查找依赖名称。他解决了以下四个场景:

  1. Optional:JDK8 提供了 API。主要是将依赖设置非强制依赖,即 descriptor.required=false。

  2. 延迟依赖注入支持:ObjectFactory、ObjectProvider、javax.inject.Provider

  3. 另一种延迟注入的支持 - @Lazy 属性。

  4. 根据类型查找依赖 - doResolveDependency。

java 复制代码
@Override
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    // ParameterNameDiscovery用于解析方法参数名称
    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    // 1. Optional<T>
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName);
    // 2. ObjectFactory<T>、ObjectProvider<T>
    } else if (ObjectFactory.class == descriptor.getDependencyType() ||
             ObjectProvider.class == descriptor.getDependencyType()) {
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    // 3. javax.inject.Provider<T>
    } else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    } else {
        // 4. @Lazy
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
            descriptor, requestingBeanName);
        // 5. 正常情况
        if (result == null) {
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
}

最底层都会调用beanFactory#doResolveDependency方法,其封装了依赖查找的各种情况。

  1. 快速查找: @Autowired 注解处理场景。AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注解时,如果注入的对象只有一个,会将该 bean 对应的名称缓存起来,下次直接通过名称查找会快很多。

  2. 注入指定值:@Value 注解处理场景。QualifierAnnotationAutowireCandidateResolver 处理 @Value 注解时,会读取 @Value 对应的值进行注入。如果是 String 要经过三个过程:①占位符处理 -> ②EL 表达式解析 -> ③类型转换,这也是一般的处理过程,BeanDefinitionValueResolver 处理 String 对象也是这个过程。

  3. 集合依赖查询:直接全部委托给 resolveMultipleBeans 方法。

  4. 单个依赖查询:先调用 findAutowireCandidates 查找所有可用的依赖,如果有多个依赖,则根据规则匹配: @Primary -> @Priority -> ③方法名称或字段名称。

java 复制代码
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        // 1. 快速查找,根据名称查找。AutowiredAnnotationBeanPostProcessor用到
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }

        // 2. 注入指定值,QualifierAnnotationAutowireCandidateResolver解析@Value会用到
        Class<?> type = descriptor.getDependencyType();
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                // 2.1 占位符解析
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                                     getMergedBeanDefinition(beanName) : null);
                // 2.2 Spring EL 表达式
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            try {
                // 2.3 类型转换
                return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
            } catch (UnsupportedOperationException ex) {
                return (descriptor.getField() != null ?
                        converter.convertIfNecessary(value, type, descriptor.getField()) :
                        converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
            }
        }

        // 3. 集合依赖,如 Array、List、Set、Map。内部查找依赖也是使用findAutowireCandidates
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }

        // 4. 单个依赖查询
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        // 4.1 没有查找到依赖,判断descriptor.require
        if (matchingBeans.isEmpty()) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;

        // 4.2 有多个,如何过滤
        if (matchingBeans.size() > 1) {
            // 4.2.1 @Primary -> @Priority -> 方法名称或字段名称匹配 
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            // 4.2.2 根据是否必须,抛出异常。注意这里如果是集合处理,则返回null
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                } else {
                    return null;
                }
            }
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        } else {
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        // 4.3 到了这,说明有且仅有命中一个
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        // 4.4 实际上调用 getBean(autowiredBeanName, type)。但什么情况下会出现这种场景?
        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());
        }
        return result;
    } finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

这里重点看下看下第四种单个依赖的查询,集合依赖与其异曲同工:

  1. 查找容器中所有可用依赖:findAutowireCandidates 方法根据类型查找依赖。

  2. 如何有多个依赖怎么处理?其实 Spring 有一套通用的流程,先按 @Primary 查找,再按 @Priority,最后按方法名称或字段名称查找,直到只有一个 bean 为止。相关的匹配规则见 determineAutowireCandidate 方法。

  3. 此时只有一个依赖,从容器获取真实的 bean。descriptor.resolveCandidate 方法根据名称 autowiredBeanName 实例化对象。

从 findAutowireCandidates 方法,我们可以看到 Spring IoC 依赖注入的来源:

  1. 先查找 Spring IoC 内部依赖 resolvableDependencies。在 AbstractApplicationContext#prepareBeanFactory 方法中默认设置了如下内部依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

  2. 在父子容器进行类型查找:查找类型匹配的 beanNames,beanFactory#beanNamesForType 方法根据类型查找是,先匹配单例实例类型(包括 Spring 托管 Bean),再匹配 BeanDefinition 的类型。从这一步,我们可以看到 Spring 依赖注入的另外两个来源:一是 Spring 托管的外部 Bean,二是 Spring BeanDefinition。

java 复制代码
protected Map<String, Object> findAutowireCandidates(
    @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
    
    Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
    // 1. Spring IoC 内部依赖 resolvableDependencies
    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;
            }
        }
    }
    
    // 2. 类型查找:本质上递归调用beanFactory#beanNamesForType。先匹配实例类型,再匹配bd。
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
        this, requiredType, true, descriptor.isEager());
    for (String candidate : candidateNames) {
        // 2.1 isSelfReference说明beanName和candidate本质是同一个对象
        //     isAutowireCandidate进一步匹配bd.autowireCandidate、泛型、@@Qualifier等进行过滤
        if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
            // 2.2 添加到候选对象中
            addCandidateEntry(result, candidate, descriptor, requiredType);
        }
    }
    
    // 3. 补偿机制:如果依赖查找无法匹配,怎么办?包含泛型补偿和自身引用补偿两种。
    if (result.isEmpty()) {
        boolean multiple = indicatesMultipleBeans(requiredType);
        // 3.1 fallbackDescriptor: 泛型补偿,实际上是允许注入对象类型的泛型存在无法解析的情况
        DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
        // 3.2 补偿1:不允许自称依赖,但如果是集合依赖,需要过滤非@Qualifier对象。什么场景?
        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
                (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        // 3.3 补偿2:允许自称依赖,但如果是集合依赖,注入的集合依赖中需要过滤自己
        if (result.isEmpty() && !multiple) {
            for (String candidate : candidateNames) {
                if (isSelfReference(beanName, candidate) &&
                    (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
                    isAutowireCandidate(candidate, fallbackDescriptor)) {
                    addCandidateEntry(result, candidate, descriptor, requiredType);
                }
            }
        }
    }
    return result;
}

findAutowireCandidates 大致可以分为三步:先查找内部依赖,再根据类型查找,最后没有可注入的依赖则进行补偿。

  1. 查找内部依赖:Spring IoC 容器本身相关依赖,这部分内容是用户而言是透明的,也不用感知。resolvableDependencies 集合中注册如 BeanFactory、ApplicationContext 、ResourceLoader、ApplicationEventPublisher 等。

  2. 根据类型查找:包括 ①外部托管 Bean ②注册 BeanDefinition。类型查找调用 beanFactory#beanNamesForType 方法。

    1. 自身引用:isSelfReference 方法判断 beanName 和 candidate 是否是同一个对象,包括两种情况:一是名称完全相同,二是 candidate 对应的工厂对象创建了 beanName。

    2. 是否可以注入:底层实际调用 resolver.isAutowireCandidate 方法进行过滤,包含三重规则:①bd.autowireCandidate=true -> ②泛型匹配 -> ③@Qualifier。下面会详细介绍这个方法。

  3. 补偿机制:如果依赖查找无法匹配,怎么办?Spring 提供了两种补偿机制:一是泛型补偿,允许注入对象对象的泛型无法解析,二是自身引用补偿,对这两种机制使用如下:

    1. 先使用泛型补偿,不允许自身引用:即 fallbackDescriptor。此时如果是集合依赖,对象必须是 @Qualifier 类型。

    2. 允许泛型补偿和自身引用补偿:但如果是集合依赖,必须过滤自己本身,即 beanName.equals(candidate) 必须剔除。

相关推荐
小曲程序4 分钟前
vue3 封装request请求
java·前端·typescript·vue
凡人的AI工具箱19 分钟前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
陈王卜22 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、22 分钟前
Spring Boot 注解
java·spring boot
java亮小白199727 分钟前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF34 分钟前
java Queue 详解
java·队列
2301_8112743144 分钟前
大数据基于Spring Boot的化妆品推荐系统的设计与实现
大数据·spring boot·后端
武子康1 小时前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
武子康1 小时前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
苏-言1 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring