spring中通过@Autowired
注入的依赖对应多个实现时,需要手动区分,告诉spring我们想注入的依赖是哪个,常见的作法有:
- 配合
@Qualifier
指定依赖名,根据依赖名找到bean进行注入 - 在依赖上标记
@Primary
注解,spring会优先注入 - 使用
@Priority
注解指定依赖的优先级,越小优先级越高 也就是说可以通过@Qualifier
+@Autowired
自动注入依赖,能够避免依赖冲突,现在看spring如何处理的。根据依赖类型找到匹配的依赖名,需要判断能否将依赖注入到属性。
java
protected boolean isAutowireCandidate(
String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
throws NoSuchBeanDefinitionException {
//根据bean定义判断能否注入
String bdName = BeanFactoryUtils.transformedBeanName(beanName);
if (containsBeanDefinition(bdName)) {
return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(bdName), descriptor, resolver);
}
//根据bena实例判断能否注入
else if (containsSingleton(beanName)) {
return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver);
}
......
}
检查能否注入时,先调用父类isAutowireCandidate
判断checkGenericTypeMatch(bdHolder, descriptor)
类型是否相同,即依赖类型和字段类型是否相同,再检查字段上标注的@Qualifier
注解。
java
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
if (match) {
match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (match) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
}
}
}
}
return match;
}
先从bean定义中获取@Qualifier
,能获取到,则说明当前依赖bean为指定的优先注入的依赖;无法获取到,则将@Qualifier
注解定义的依赖名和实际依赖bean的名称进行比较,相同的话说明根据@Qualifier
注解找到指定的依赖了,进行注入即可。
java
protected boolean checkQualifier(
BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) {
//获取字段的@Qualifier注解
Class<? extends Annotation> type = annotation.annotationType();
RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
..... //从bean定义上获取@Qualifier注解,如果能获取到,则优先注入
if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
return true;
}
//依赖上没有@Qualifier注解,则通过依赖bean名是否和@Qualifier注解属性相同判断能否注入
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
if (attributes.isEmpty() && qualifier == null) {
// If no attributes, the qualifier must be present
return false;
}
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String attributeName = entry.getKey();
Object expectedValue = entry.getValue();
Object actualValue = null;
// Check qualifier first
if (qualifier != null) {
actualValue = qualifier.getAttribute(attributeName);
}
if (actualValue == null) {
// Fall back on bean definition attribute
actualValue = bd.getAttribute(attributeName);
}
//判断@Qualifier指定依赖名和实际依赖名是否相同
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) {
// Fall back on bean name (or alias) match
continue;
}
if (actualValue == null && qualifier != null) {
// Fall back on default, but only if the qualifier is present
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
}
if (actualValue != null) {
actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
}
if (!expectedValue.equals(actualValue)) {
return false;
}
}
return true;
}
总结下,spring处理通过@Autowired
结合@Qualifier
注入依赖时,先判断类型,再判断依赖上是否存在@Qualifier
,不存在的话再通过@Qualifier
属性指定的名称跟依赖名比较判断能否注入依赖,更多请关注微信公众号 葡萄开源