spring @Primary注解源码分析

当一个接口有2个不同实现时,使用@Autowired注解时会报

org.springframework.beans.factory.NoUniqueBeanDefinitionException异常信息

因为@Autowired, 默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口,可能会有几种不同的实现类。

解决方案

1.用@Qualifier这个注解来解决问题

2.@Primary

Primary可以理解为默认优先选择,且不可以同时设置超过1个
内部实质是设置BeanDefinition的primary属性

源码解析:

在创建bean的时候,我们会获取bean的依赖bean,这个方法就是DefaultListableBeanFactory的doResolveDependency方法,如果匹配的bean大于1,会执行如下方法:

 @Nullable
    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);

        String autowiredBeanName;
        try {
            Object shortcut = descriptor.resolveShortcut(this);
            if (shortcut != null) {
                Object var20 = shortcut;
                return var20;
            }

            Class<?> type = descriptor.getDependencyType();
            Object value = this.getAutowireCandidateResolver().getSuggestedValue(descriptor);
            Object var23;
            if (value != null) {
                if (value instanceof String) {
                    String strVal = this.resolveEmbeddedValue((String)value);
                    BeanDefinition bd = beanName != null && this.containsBean(beanName) ? this.getMergedBeanDefinition(beanName) : null;
                    value = this.evaluateBeanDefinitionString(strVal, bd);
                }

                TypeConverter converter = typeConverter != null ? typeConverter : this.getTypeConverter();

                try {
                    var23 = converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
                    return var23;
                } catch (UnsupportedOperationException var18) {
                    Object var25 = descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter());
                    return var25;
                }
            }

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

            Map<String, Object> matchingBeans = this.findAutowireCandidates(beanName, type, descriptor);
            if (!matchingBeans.isEmpty()) {
                Object instanceCandidate;
                Object result;
                //如果匹配的bean大于1,执行determineAutowireCandidate方法
                if (matchingBeans.size() > 1) {
                    autowiredBeanName = this.determineAutowireCandidate(matchingBeans, descriptor);
                    if (autowiredBeanName == null) {
                        if (!this.isRequired(descriptor) && this.indicatesMultipleBeans(type)) {
                            result = null;
                            return result;
                        }

                        result = descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                        return result;
                    }

                    instanceCandidate = matchingBeans.get(autowiredBeanName);
                } else {
                    Entry<String, Object> entry = (Entry)matchingBeans.entrySet().iterator().next();
                    autowiredBeanName = (String)entry.getKey();
                    instanceCandidate = entry.getValue();
                }

                if (autowiredBeanNames != null) {
                    autowiredBeanNames.add(autowiredBeanName);
                }

                if (instanceCandidate instanceof Class) {
                    instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
                }

                result = instanceCandidate;
                if (instanceCandidate instanceof NullBean) {
                    if (this.isRequired(descriptor)) {
                        this.raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                    }

                    result = null;
                }

                if (!ClassUtils.isAssignableValue(type, result)) {
                    throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
                }

                Object var14 = result;
                return var14;
            }

            if (this.isRequired(descriptor)) {
                this.raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }

            autowiredBeanName = null;
        } finally {
            ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
        }

        return autowiredBeanName;
    }

下面进入到determineAutowireCandidate方法中:

@Nullable
    protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
        Class<?> requiredType = descriptor.getDependencyType();
        String primaryCandidate = this.determinePrimaryCandidate(candidates, requiredType);
        if (primaryCandidate != null) {
            return primaryCandidate;
        } else {
            String priorityCandidate = this.determineHighestPriorityCandidate(candidates, requiredType);
            if (priorityCandidate != null) {
                return priorityCandidate;
            } else {
                Iterator var6 = candidates.entrySet().iterator();

                String candidateName;
                Object beanInstance;
                do {
                    if (!var6.hasNext()) {
                        return null;
                    }

                    Entry<String, Object> entry = (Entry)var6.next();
                    candidateName = (String)entry.getKey();
                    beanInstance = entry.getValue();
                } while((beanInstance == null || !this.resolvableDependencies.containsValue(beanInstance)) && !this.matchesBeanName(candidateName, descriptor.getDependencyName()));

                return candidateName;
            }
        }
    }

然后进入到determinePrimaryCandidate方法中:

    @Nullable
    protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
        String primaryBeanName = null;
        Iterator var4 = candidates.entrySet().iterator();

        while(var4.hasNext()) {
            Entry<String, Object> entry = (Entry)var4.next();
            String candidateBeanName = (String)entry.getKey();
            Object beanInstance = entry.getValue();
            if (this.isPrimary(candidateBeanName, beanInstance)) {
                if (primaryBeanName != null) {
                    boolean candidateLocal = this.containsBeanDefinition(candidateBeanName);
                    boolean primaryLocal = this.containsBeanDefinition(primaryBeanName);
                    //isPrimary方法是判断是否有@Primary注解,如果有多个满足条件的bean有@Primary注解就会抛出异常:
                    if (candidateLocal && primaryLocal) {
                        throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "more than one 'primary' bean found among candidates: " + candidates.keySet());
                    }

                    if (candidateLocal) {
                        primaryBeanName = candidateBeanName;
                    }
                } else {
                    primaryBeanName = candidateBeanName;
                }
            }
        }

        return primaryBeanName;
    }

例子:

public interface Singer {
    String sing(String lyrics);
}

有下面的两个实现类:

@Component // 加注解,让spring识别
public class MetalSinger implements Singer{

    @Override
    public String sing(String lyrics) {
        return "I am singing with DIO voice: "+lyrics;
    }
}

//注意,这里没有注解

public class OperaSinger implements Singer {
    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: "+lyrics;
    }
}

下面就是注入上面的

@Component
 public class SingerService {
        private static final Logger logger = LoggerFactory.getLogger(SingerService.class);
    @Autowired
    private Singer singer;
    public String sing(){
        return singer.sing("song lyrics");
    }
   }

I am singing with DIO voice: song lyrics. 原因很简单,就是 OperaSinger 这个类上面根本没有加上注解@Copmonent 或者 @Service, 所以spring 注入的时候,只能找到 MetalSinger 这个实现类. 所以才有这个结果。

但是如果一旦 OperaSinger 这个类加上了@Copmonent 或者 @Service 注解,有趣的事情就会发生,你会发现一个错误的结果或异常:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [main.service.Singer] is defined: expected single matching bean but found 2: metalSinger,operaSinger

提示很明确了,spring 根据类型无法选择到底注入哪一个。这个时候@Primay 可以闪亮登场了。

@Primary
@Component
public class OperaSinger implements Singer{

    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: "+lyrics;
    }
}

如果代码改成这样,再次运行,结果如下:
“I am singing in Bocelli voice: song lyrics”, 用@Primary 告诉spring 在犹豫的时候优先选择哪一个具体的实现。

二、用@Qualifier这个注解来解决问题

将上面的两个类改为如下:

@Component // 加注解,让spring识别
@Qualifier("metalSinger")
public class MetalSinger implements Singer{

    @Override
    public String sing(String lyrics) {
        return "I am singing with DIO voice: "+lyrics;
    }
}

@Component
@Qualifier("opreaSinger")
public class OperaSinger implements Singer {
    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: "+lyrics;
    }
}
@Component
public class SingerService {
    private static final Logger logger = LoggerFactory.getLogger(SingerService.class);

    @Autowired
    private Singer singer;

    @Qualifier("opreaSinger")
    public String sing(){
        return singer.sing("song lyrics");
    }
}

参考:https://blog.csdn.net/lz710117239/article/details/81192761

原创文章 317 获赞 416 访问量 112万+

猜你喜欢

转载自blog.csdn.net/u014082714/article/details/100554070