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

相关文章
相关标签/搜索