@Qualifier依赖注入原理

spring中通过@Autowired注入的依赖对应多个实现时,需要手动区分,告诉spring我们想注入的依赖是哪个,常见的作法有:

  1. 配合@Qualifier指定依赖名,根据依赖名找到bean进行注入
  2. 在依赖上标记@Primary注解,spring会优先注入
  3. 使用@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属性指定的名称跟依赖名比较判断能否注入依赖,更多请关注微信公众号 葡萄开源

相关推荐
学长毕设1 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
滴滴答答哒2 小时前
ASP.NET Core + FaceRecognitionDotNet 人脸识别实战:DI 单例、特征向量持久化与 1:N 比对
后端·asp.net
captain3764 小时前
MyBatis操作数据库(入门2)
java·数据库·spring boot·后端·spring·mybatis
IT_陈寒5 小时前
Java序列化踩坑记:对象循环引用让我加班两小时
前端·人工智能·后端
泡海椒6 小时前
05-雷达图多维画像-信用评级多维画像
后端
王中阳Go6 小时前
5.27 分钟干完后端和全部测试:一场三小时笔试的五个失分点,四个不在代码上
大数据·数据库·人工智能·后端·大语言模型
大哥43096 小时前
Modbus 的"字序":一个配错就变成天文数字,或者干脆变成 0
后端
岩钧6 小时前
New API 源码解析:一个生产级 AI 网关的架构与实现
后端
学到老活到老6 小时前
第 24 集:配置文件写了 80,Spring Boot 为什么读到 90?
java·后端·spring
用户360055579006 小时前
Kestrel_VLLM - 25 · 全注意力层设备化、整层对拍与访存粒度
后端