spring自動裝配優先級處理

spring版本5.0.4java

spring的自動裝配 咱們通常經過加註解的方式來實現,@Resource 或者@Autowired。處理自動裝配的類爲DefaultListableBeanFactory,部分源碼以下:spring

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

   InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
   try {
      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()));
      }

      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
         return multipleBeans;
      }

      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;

      if (matchingBeans.size() > 1) {
        //有多個bean匹配執行determinaAutowireCandidate方法獲取最終匹配的bean
         autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
         if (autowiredBeanName == null) {
            if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
               return descriptor.resolveNotUnique(type, matchingBeans);
            }

若是存在實現相同接口的多個類實例化在spring容器中的時候,這種狀況本人在項目中有遇到,不一樣實如今不一樣的maven模塊,根據打包不一樣的maven模塊注入不一樣的實現,對於相似狀況的處理,咱們須要用到裝配的優先級處理,spring在自動裝配時是支持裝配優先級的處理的,下面貼一下spirng自動裝配的源碼和我的的分析,忘能幫助遇到類型狀況的小夥伴。spring自動裝配的規則以下:maven

/**
 * Determine the autowire candidate in the given set of beans.
 * <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
 * @param candidates a Map of candidate names and candidate instances
 * that match the required type, as returned by {@link #findAutowireCandidates}
 * @param descriptor the target dependency to match against
 * @return the name of the autowire candidate, or {@code null} if none found
 */
@Nullable
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
   Class<?> requiredType = descriptor.getDependencyType();
   //根據@Primary註解進行肯定
   String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
   if (primaryCandidate != null) {
      return primaryCandidate;
   }
   //根據@Priority註解進行肯定
   String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
   if (priorityCandidate != null) {
      return priorityCandidate;
   }
   // Fallback
   for (Map.Entry<String, Object> entry : candidates.entrySet()) {
      String candidateName = entry.getKey();
      Object beanInstance = entry.getValue();
      if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
            //根據beanName和fieldName是否匹配肯定
            matchesBeanName(candidateName, descriptor.getDependencyName())) {
         return candidateName;
      }
   }
   return null;

1.按照bean加了@Primary註解進行匹配,若是存在多個bean有@Primary,會報錯,源碼截圖以下ui

/**
 * Determine the primary candidate in the given set of beans.
 * @param candidates a Map of candidate names and candidate instances
 * (or candidate classes if not created yet) that match the required type
 * @param requiredType the target dependency type to match against
 * @return the name of the primary candidate, or {@code null} if none found
 * @see #isPrimary(String, Object)
 */
@Nullable
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
   String primaryBeanName = null;
   for (Map.Entry<String, Object> entry : candidates.entrySet()) {
      String candidateBeanName = entry.getKey();
      Object beanInstance = entry.getValue();
      if (isPrimary(candidateBeanName, beanInstance)) {
         if (primaryBeanName != null) {
            boolean candidateLocal = containsBeanDefinition(candidateBeanName);
            boolean primaryLocal = containsBeanDefinition(primaryBeanName);
            if (candidateLocal && primaryLocal) {
               throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
                     "more than one 'primary' bean found among candidates: " + candidates.keySet());
            }
            else if (candidateLocal) {
               primaryBeanName = candidateBeanName;
            }
         }
         else {
            primaryBeanName = candidateBeanName;
         }
      }
   }
   return primaryBeanName;
}

2.按照bean加了@Priority進行匹配,@Priority的值越小,優先級越高,若是存在兩個相同最高的優先級,會報錯this

/**
 * Determine the candidate with the highest priority in the given set of beans.
 * <p>Based on {@code @javax.annotation.Priority}. As defined by the related
 * {@link org.springframework.core.Ordered} interface, the lowest value has
 * the highest priority.
 * @param candidates a Map of candidate names and candidate instances
 * (or candidate classes if not created yet) that match the required type
 * @param requiredType the target dependency type to match against
 * @return the name of the candidate with the highest priority,
 * or {@code null} if none found
 * @see #getPriority(Object)
 */
@Nullable
protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
   String highestPriorityBeanName = null;
   Integer highestPriority = null;
   for (Map.Entry<String, Object> entry : candidates.entrySet()) {
      String candidateBeanName = entry.getKey();
      Object beanInstance = entry.getValue();
      if (beanInstance != null) {
         Integer candidatePriority = getPriority(beanInstance);
         if (candidatePriority != null) {
            if (highestPriorityBeanName != null) {
               if (candidatePriority.equals(highestPriority)) {
                  throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
                        "Multiple beans found with the same priority ('" + highestPriority +
                        "') among candidates: " + candidates.keySet());
               }
               else if (candidatePriority < highestPriority) {
                  highestPriorityBeanName = candidateBeanName;
                  highestPriority = candidatePriority;
               }
            }
            else {
               highestPriorityBeanName = candidateBeanName;
               highestPriority = candidatePriority;
            }
         }
      }
   }
   return highestPriorityBeanName;
}

3.按照名稱進行匹配(beanName和fieldName)lua

// Fallback
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
   String candidateName = entry.getKey();
   Object beanInstance = entry.getValue();
   if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
         matchesBeanName(candidateName, descriptor.getDependencyName())) {
      return candidateName;
   }
}

若是沒法肯定自動裝配的bean,報錯: No qualifying bean of type '類型' available: expected single matching bean but found 多個bean匹配spa

能夠根據實際須要,配置優先級.net

相關文章
相關標籤/搜索