@Autowired 如何不使用 @Qualifier 也能注入想要的具体实现

        在一次开发中,偶然间发现使用@Autowired注入有多个实现的对象时,并未通过@Qualifier定义想要的实现,代码也成功启动并且注入了自己想要的具体实现类。按照以往对@Autowired的理解:@Autowired是按照类型来注入bean的,如果有多个实现需要通过@Qualifier指定要注入的具体的bean的名称。

        为了弄明白Spring具体做了什么,于是一步一步的去调试了整个bean的创建过程。

        先创建一个父类 Car,其中定义了一个方法name

public interface Car {

    String name();

}

        然后创建它的两个子类 BMW 和 BYD

@Component("byd")
public class BYD implements Car{

    @Override
    public String name() {
        System.out.println("I'm BYD");
        return "BYD";
    }
}
@Component("bmw")
public class BMW implements Car{

    @Override
    public String name() {
        System.out.println("I'm BMW");
        return "BMW";
    }
}

        最后在要使用的地方通过@Autowired注入 Car。

        首先我们通过如下方式注入:

Car car;

@Autowired
public void setCar(@Qualifier("bmw") Car car) {
    this.car = car;
}

        会发现 idea 会有提示报错无法自动装配。存在多个‘Car’类型的Bean。Beans:bmw,byd。

         根据提示加上@Qualifier("bmw")或者@Qualifier("byd")自然能解决这个问题,但是我们尝试使用如下方式:

Car bmw;
@Autowired
public void setCar(Car bmw) {
    this.bmw = bmw;
}

        此时发现报错没有了,启动程序运行bmw.name()方法,发现返回为 "BMW",属性名称和构造器传入参数更换为 "byd",重新启动程序运行 byd.name()方法,发现返回 "BYD"。 那具体是怎么做到的呢?

        我们点开@Autowired注解发现它让我们去看AutowiredAnnotationBeanPostProcessor这个类,看名称知道这是Spring中bean的生命周期中的bean后置处理器(spring生命周期相关此处不赘述)且是用于处理@Autowired注解的一个后置处理器。

点开 AutowiredAnnotationBeanPostProcessor 源码,找到,其中的代码主要是获取了类中的@Autowired数据。找到postProcessProperties()方法中findAutowiringMetadata方法中代码如下:

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        ...
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                    metadata = buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        }

        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

            // 寻找有@Autowired的field
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    // 找到的field封装成AutowiredFieldElement放入currElements
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
                }
            });
            // 寻找有@Autowired的method
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    if (method.getParameterCount() == 0) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    boolean required = determineRequiredStatus(ann);
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    // 找到的field封装成AutowiredMethodElement放入currElements
                    currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                }
            });

            // 将currElements全部添加到elements中
            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        // 调用InjectionMetadata的forElements方法传入elements封装成InjectionMetadata对象
        return InjectionMetadata.forElements(elements, clazz);
    }

         其中主要的代码加了注释,包括doWithLocalFields()方法获取有@Autowired属性(属性注入)和doWithLocalMethods()方法获取有@Autowired的方法(构造方法注入和setter方法注入)。最后全部封装成一个InjectionMetadata对象。

        接着分析 AutowiredAnnotationBeanPostProcessor 源码中postProcessProperties()方法中metadata.inject(bean, beanName, pvs)方法:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
				if (logger.isTraceEnabled()) {
					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
				}
                // 遍历每个元素来注入
				element.inject(target, beanName, pvs);
			}
		}
	}

        其中最为关键的方法是element.inject(target, beanName, pvs),它把在findAutowiringMetadata中生成的InjectionMetadata对象中所有的InjectedElement进行遍历,对每个需要注入的元素调用他自身的element.inject(target, beanName, pvs)方法。上边我们说到了,InjectedElement分别有AutowiredFieldElement(属性)和AutowiredMethodElement(setter方法,构造器方法)两种,先追踪AutowiredFieldElement。点开AutowiredFieldElement的inject方法:

    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				...
				try {
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
				}
				...
			}
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}

        其中有行代码为beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter),看名字应该是我们需要追踪的代码(因为最后把该方法的value值设置给了field的,也可以自己去追踪确定,这里直接得结论),它的实现是在DefaultListableBeanFactory,点进去查看:

    @Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

        了解过Spring源码的码友可能都会发现Spring中的do开头的方法一般就是实际执行操作逻辑的部分,于是我们找到doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter)方法,继续深入:

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

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			...
			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
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

        其中关于getAutowireCandidateResolver().getSuggestedValue(descriptor)和resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter)笔者没有去深入研究过,想来是一些其他的获取注入值。我们主要关注findAutowireCandidates(beanName, type, descriptor)方法,它返回了需要注入的属性的所有匹配的bean,此处返回的是BMW和BYD两个子类。接着通过后边的determineAutowireCandidate(matchingBeans, descriptor)获取到确切的需要注入的beanName,最后通过matchingBeans.get(autowiredBeanName)获取到注入的bean。继续深入:

@Nullable
	protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
		Class<?> requiredType = descriptor.getDependencyType();
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		if (primaryCandidate != null) {
			return primaryCandidate;
		}
		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)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				return candidateName;
			}
		}
		return null;
	}

        可以看到在这个方法中先进行了Primary判断和Highest判断(具体逻辑读者自己深入阅读),之后会对所有匹配的遍历获取到它的beanName和具体实现,在if里边判断了matchesBeanName(candidateName, descriptor.getDependencyName()),其中执行了一段代码为:

return (candidateName != null &&
				(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));

可以看出如果匹配的bean的beanName和属性名一致,或者是别名一致就会匹配成功。至此,Spring如何在没使用@Qualifier的情况下,只是通过吧field的名称与需要注入的bean的beanName一致也成功注入了想要的bean。在构造器注入和setter注入下,则需要在构造函数的参数名称与beanName一致才会注入想要的bean,具体代码请读者自行阅读。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值