Spring IOC(六)依賴查找

Spring IOC(六)依賴查找

Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

Spring BeanFactory 的實現有三個重要的類,功能以下:java

  • AbstractBeanFactory 實現了 BeanFactory、 HierarchicalBeanFactory、ConfigurableBeanFactory 三個接口,最重要的方法是實現了 getBean(beanName) 接口,這個方法的最重要的步驟-建立 bean 則委託給模板方法 createBean 完成。git

  • AbstractAutowireCapableBeanFactory 實現了 AutowireCapableBeanFactory 接口,也就是依賴注入。同時實現了 crcreateBean(beanName, mbd, args) 建立 bean 的三個重要過程:實例化(createBeanInstance)、依賴注入(populateBean)、初始化(initializeBean)。其中依賴注入又分爲 autowireByName 和 autowireByType 二種,其中名稱查找很簡單,而類型查找就複雜了不少。Spring 將類型查找委託給了子類的 resolveDependency 完成。github

  • DefaultListableBeanFactory 實現了 ConfigurableListableBeanFactory、BeanDefinitionRegistry 兩個接口,提供了 Bean 和 BeanDefinition 查找註冊的功能。 這個類一個很重要的功能是實現了模板方法 resolveDependency,這樣就能夠根據類型查找依賴。spring

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

1、名稱查找 - autowireByName

毫無疑問,直接從 BeanFactory 中取出這個 bean 就能夠了。app

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

2、類型查找 - autowireByType

autowireByType 相比 autowireByName 就複雜多了,不過 autowireByType 直接委託給 resolveDependency 方法了,ide

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 進行了實現,做用就是根據類型查找依賴。ui

3、查找依賴 - resolveDependency

3.1 入口 - resolveDependency

先解釋一下 resolveDependency 這個方法的四個參數:this

  • 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


天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索