zoukankan      html  css  js  c++  java
  • Spring IOC(六)依赖查找

    Spring IOC(六)依赖查找

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

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

    • AbstractBeanFactory 实现了 BeanFactory、 HierarchicalBeanFactory、ConfigurableBeanFactory 三个接口,最重要的方法是实现了 getBean(beanName) 接口,这个方法的最重要的步骤-创建 bean 则委托给模板方法 createBean 完成。

    • AbstractAutowireCapableBeanFactory 实现了 AutowireCapableBeanFactory 接口,也就是依赖注入。同时实现了 crcreateBean(beanName, mbd, args) 创建 bean 的三个重要过程:实例化(createBeanInstance)、依赖注入(populateBean)、初始化(initializeBean)。其中依赖注入又分为 autowireByName 和 autowireByType 二种,其中名称查找很简单,而类型查找就复杂了很多。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 方法。
        //    注意 getBeanNamesForType 方法会过滤别名的情况
        String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this, requiredType, true, descriptor.isEager());
    
        // 2. 先查找缓存中 requiredType 的依赖,ok
        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. 如果是非循环引用并且是合法的,ok
        for (String candidate : candidateNames) {
            // 所谓的循环引用是指 candidateName 实例的工厂就是 beanName 或就是本身
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
    
        // 4. 如果没有找到,有两种解决方案:一是回退操作,如 @Autowire 回退到名称查找,二是非集合类型考虑循环引用
        if (result.isEmpty()) {
            // 判断要注入的类型是 Array、Map、Collection
            boolean multiple = indicatesMultipleBeans(requiredType);
            // 4.1 先执行回退操作
            DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
            for (String candidate : candidateNames) {
                if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
                        (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
                    addCandidateEntry(result, candidate, descriptor, requiredType);
                }
            }
            // 4.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 都是真正中 BeanFactory 容器中根据类型查找,主要有以下几个步骤:

    1. 从本容器和父容器中查找所有的该类型的 candidateNames
    2. 从缓存中查找该类型的 bean
    3. 从 candidateNames 过滤可用的 bean,过滤规则有两个:一是非循环引用;二是符合 AutowireCandidateResolver 的规则。默认实现为 SimpleAutowireCandidateResolver,根据 BeanDefinition#autowireCandidate 字段判断,默认为 true。
    4. 如果过滤后没有可用的 bean 了,这时考虑回退操作和循环引用。回退时如 @Autowire 回退到名称查找。回退还查找不到可用的就考虑循环引用的情况。

    (1) 循环引用

    // candidateName 实例的工厂就是 beanName 或就是本身
    private boolean isSelfReference(@Nullable String beanName, @Nullable String candidateName) {
        return (beanName != null && candidateName != null &&
                (beanName.equals(candidateName) || (containsBeanDefinition(candidateName) &&
                        beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName()))));
    }
    

    举个例子:

    // <bean id="company" autowire="byType" class="com.github.binarylei.Company"/>
    @Test
    public void test() {
        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(lbf);
        reader.loadBeanDefinitions(new ClassPathResource("spring-context-di-2.xml", getClass()));
    
        Company company = (Company) lbf.getBean("company");
    }
    
    public static class Company {
        private Company company;
        private List<Company> companies;
        // 省略 setter
    }
    

    上面的例子中 company 字段虽然有循环依赖的问题,依然可以正常注入,但其集合类型 companies 无法注入。

    (2) 是否可用 isAutowireCandidate

    DependencyDescriptor 对字段、方法参数、构造器参数进行统一的封装,配合 AutowireCandidateResolver 类一起解决依赖查找的问题。

    @Override
    public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
            throws NoSuchBeanDefinitionException {
        return isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver());
    }
    
    protected boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
            throws NoSuchBeanDefinitionException {
        String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
        if (containsBeanDefinition(beanDefinitionName)) {
            return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanDefinitionName), descriptor, resolver);
        } else if (containsSingleton(beanName)) {
            return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver);
        }
    
        BeanFactory parent = getParentBeanFactory();
        if (parent instanceof DefaultListableBeanFactory) {
            return ((DefaultListableBeanFactory) parent).isAutowireCandidate(beanName, descriptor, resolver);
        } else if (parent instanceof ConfigurableListableBeanFactory) {
            return ((ConfigurableListableBeanFactory) parent).isAutowireCandidate(beanName, descriptor);
        } else {
            return true;
        }
    }
    
    protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
            DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
        // 如果只有唯一的工厂方法,先解析出来。以后再来研究干什么用的???
        String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
        resolveBeanClass(mbd, beanDefinitionName);
        if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
            new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
        }
        // 调用 AutowireCandidateResolver#isAutowireCandidate 方法判断是否可用
        return resolver.isAutowireCandidate(
                new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor);
    }
    

    isAutowireCandidate 最终调用了 AutowireCandidateResolver#isAutowireCandidate 方法,以 SimpleAutowireCandidateResolver 为例:

    @Override
    public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
        return bdHolder.getBeanDefinition().isAutowireCandidate();
    }
    

    Spring 默认判断 BeanDefinition#autowireCandidate 属性,一般默认为 true。

    3.3 doResolveDependency

    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
                @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
        // 将当前正在解决的依赖存放到 ThreadLocal 中,作用以后再研究???
        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
        try {
            // 1. resolveShortcut 和 getSuggestedValue 都是对依赖解析前的拦截,这也很符全 Spring 的做法
            Object shortcut = descriptor.resolveShortcut(this);
            if (shortcut != null) {
                return shortcut;
            }
    
            Class<?> type = descriptor.getDependencyType();
            Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
            if (value != null) {
                if (value instanceof String) {
                    String strVal = resolveEmbeddedValue((String) value);
                    BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
                    value = evaluateBeanDefinitionString(strVal, bd);
                }
                TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
                return (descriptor.getField() != null ?
                        converter.convertIfNecessary(value, type, descriptor.getField()) :
                        converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
            }
    
            // 2. 匹配多个,sine @Spring 4.3。如果 type 是 Array、List、Map 走这里,当然也有可以匹配不到
            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
            if (multipleBeans != null) {
                return multipleBeans;
            }
    
            // 3. 正常流程,只匹配一个,先找到所有可用的 matchingBeans
            //    如果有多个,则比较优先级确定一个
            //    如果没有,则根据依赖是否是必需的抛出异常
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }
    
            String autowiredBeanName;
            Object instanceCandidate;
    
            // 3.1 匹配到多个,则根据优先级选一个。注意集合类型允许为空
            if (matchingBeans.size() > 1) {
                // 3.1.1 根据 Primary 属性或 PriorityOrdered 接口指定优先级
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                if (autowiredBeanName == null) {
                    // 3.1.2 如果是必需的或非集合类型,那么就根据 DependencyDescriptor 指定的规则选择一个最优的
                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                        return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                    // 3.1.3 集合类型允许为 null
                    } else {
                        return null;
                    }
                }
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            // 3.2 精确匹配一个
            } else {
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }
    
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(autowiredBeanName);
            }
            if (instanceCandidate instanceof Class) {
                instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
            }
    
            // 4. 校验
            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);
        }
    }
    

    doResolveDependency 这个方法有点长,大概可以分为三步:

    1. 首先是前面的拦截处理,这两个拦截肯定是扩展用的。
    2. 依赖查找。有两种情况:一是集合注入,查找使用 resolveMultipleBeans;二是匹配单个,查找使用 findAutowireCandidates。
    3. 依赖校验。一是如果查找到多个,如何匹配优先级;二是如果没有是否抛出异常。

    findAutowireCandidates 方法我们前面已经看过了,根据类型查找所有的依赖。其实 resolveMultipleBeans 也是调用这个方法。我们只看一下 List 集合是怎么处理的:

    if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
        // 1. 解析泛型的真实类型 eg List<User> 是 User
        Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
        if (elementType == null) {
            return null;
        }
        // 2. 调用 findAutowireCandidates 查找所有的类型
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
                new MultiElementDescriptor(descriptor));
        if (matchingBeans.isEmpty()) {
            return null;
        }
        if (autowiredBeanNames != null) {
            autowiredBeanNames.addAll(matchingBeans.keySet());
        }
        // 3. 类型转换
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
        Object result = converter.convertIfNecessary(matchingBeans.values(), type);
        // 4. 排序
        if (result instanceof List) {
            Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
            if (comparator != null) {
                ((List<?>) result).sort(comparator);
            }
        }
        return result;
    }
    

    至此,根据类型查找依赖已经完成。

    参考:

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


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

  • 相关阅读:
    20200726 千锤百炼软工人第二十一天
    20200725 千锤百炼软工人第二十天
    20200724 千锤百炼软工人第十九天
    20200723 千锤百炼软工人第十八天
    20200722 千锤百炼软工人第十七天
    20200721 千锤百炼软工人第十六天
    剑指Offer_#64_求1+2+…+n
    剑指Offer_#63_股票的最大利润
    剑指Offer_#62_圆圈中最后剩下的数字
    剑指Offer_#61_扑克牌中的顺子
  • 原文地址:https://www.cnblogs.com/binarylei/p/10340455.html
Copyright © 2011-2022 走看看