Spring IOC(二)依赖查找

Spring IOC(二)依赖查找

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)

Spring BeanFactory 的三个重要的实现类功能如下:

  • AbstractBeanFactory 实现了 BeanFactory、 HierarchicalBeanFactory、ConfigurableBeanFactory 三个接口,最终要的是实现了 getBean(beanName) 查找的接口,但最重要的一个模板方法 createBean 委托给子类完成。

  • AbstractAutowireCapableBeanFactory 实现了 AutowireCapableBeanFactory 接口,也就是依赖注入。同时实现了 crcreateBean(beanName, mbd, args) 的三个重要过程:实例化(createBeanInstance)、依赖注入(populateBean)、初始化(initializeBean)。其中依赖注入又分为 beanName 和 type 二种,其中名称查找很简单,而类型查找就复杂了很多。Spring 将类型查找委托给了子类的 resolveDependency 完成。

  • DefaultListableBeanFactory 实现了 ConfigurableListableBeanFactory、BeanDefinitionRegistry 两个接口,提供了 Bean 和 BeanDefinition 查找注册的功能。 这个类一个很重要的功能是实现了模板方法 resolveDependency,这样就可以根据类型查找依赖。

在 populateBean(beanName, mbd, bw) 中可以看到有两种 bean 的查找方法:名称查找和类型查找,下面我们来分析一下这两种查找方式。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || 
            mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
}

一、名称查找 - autowireByName

毫无疑问,直接从 BeanFactory 中取出这个 bean 就可以了。

protected void autowireByName(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
            Object bean = getBean(propertyName);
            pvs.add(propertyName, bean);
            registerDependentBean(propertyName, beanName);
        }
    }
}

二、类型查找 - autowireByType

autowireByType 相比 autowireByName 就复杂多了,不过 autowireByType 直接委托给 resolveDependency 方法了,

protected void autowireByType(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            if (Object.class != pd.getPropertyType()) {
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // 类型查找时允许对 FactoryBean 提前实例化对象,大部分情况一都是 true。
                // 至于为什么实现了 PriorityOrdered 接口的 bean 要排除,以后再研究一下???
                boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);

                // 核心代码就这一句,类型查找委托给了子类的 resolveDependency 完成
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    registerDependentBean(autowiredBeanName, beanName);
                }
                autowiredBeanNames.clear();
            }
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(ex);
        }
    }
}

resolveDependency(desc, beanName, autowiredBeanNames, converter) 可以说是 AbstractAutowireCapableBeanFactory 最重要的模板方法了,子类 DefaultListableBeanFactory 进行了实现,作用就是根据类型查找依赖。

三、依赖查找 - resolveDependency

3.1 入口 - resolveDependency

先解释一下 resolveDependency 这个方法的四个参数:

  • descriptor DependencyDescriptor 这个类实现了对字段、方法参数、构造器参数的进行依赖注入时的统一访问方式,你可以简单的认为是对这三种类型的封装。
  • requestingBeanName 外层的 beanName
  • autowiredBeanNames 根据类型查找可能有多个,autowiredBeanNames 就是指查找到的 beanName 集合,Spring 支持 Array、Map、Collection 的注入。
  • typeConverter 类型转换器,BeanWrapper 自己就是一个转换器。
@Override
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

    Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
            descriptor, requestingBeanName);
    if (result == null) {
        result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    }
    return result;  
}

resolveDependency 方法将最重要的实现委托给了 doResolveDependency 完成。这里有两个类需要简单的说明一下:ParameterNameDiscovery 和 AutowireCandidateResolver。

  • ParameterNameDiscovery 这个类用于查找方法的参数的名称,默认的实现有 StandardReflectionParameterNameDiscoverer。详见:<>
  • AutowireCandidateResolver 策略接口,对特定的依赖,这个接口决定一个特定的 BeanDefinition 是否满足作为自动绑定的备选项。

3.2 findAutowireCandidates

在分析 doResolveDependency 方法之前,先看一下 findAutowireCandidates,这个方法是根据类型在容器中查找到所有可用的 bean。

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

    // 1. 根据类型查找父子容器中所有可用的 beanName,调用 getBeanNamesForType 方法。
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this, requiredType, true, descriptor.isEager());

    // 2. 先查找 resolvableDependencies 中的依赖,外部扩展使用,先忽略
    Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
    for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
        Class<?> autowiringType = classObjectEntry.getKey();
        if (autowiringType.isAssignableFrom(requiredType)) {
            Object autowiringValue = classObjectEntry.getValue();
            // 可能为一个 ObjectFactory 对象,调用 getObject 获取真实的对象
            autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
            if (requiredType.isInstance(autowiringValue)) {
                result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                break;
            }
        }
    }

    // 3. 先将合法的添加进去。eg: isSelfReference(”beanName“, ”&beanName“)=true
    for (String candidate : candidateNames) {
        if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
            addCandidateEntry(result, candidate, descriptor, requiredType);
        }
    }

    // 4. 没有时进行回退操作,如 @Autowire 回退到名称
    if (result.isEmpty()) {
        boolean multiple = indicatesMultipleBeans(requiredType);
        // Consider fallback matches if the first pass failed to find anything...
        DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
                    (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        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);
                }
            }
        }
    }
    return result;
}

参考:

1 . 《Spring各种依赖注入注解的区别》:https://blog.csdn.net/gaohe7091/article/details/39319363


每天用心记录一点点。内容也许不重要,但习惯很重要!

猜你喜欢

转载自www.cnblogs.com/binarylei/p/10340455.html