@Autowired注解分析

354 阅读6分钟

创建实例的具体过程本篇不再赘述,可以参见通过spring源码分析bean的实例化过程这篇文章,本篇主要是针对@Autowired实现的注入做一分析。

1、AbstractAutowireCapableBeanFactory#doCreateBean

这个方法代码比较多,这里只将这个方法在本次源码分析中密切相关的两个方法列出来

  • 1、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  • 2、populateBean(beanName, mbd, instanceWrapper); 在执行1出的代码时,已经“完成了”实例化,为什么加了引号,是因为此时实例化的对象还没有给属性赋值。 那么在执行1处的代码时,就会执行满足条件的所有的后置处理器。

2、AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors

	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof MergedBeanDefinitionPostProcessor) {
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
			}
		}
	}

其中,会执行到这么一个后置处理器对应的方法

3、AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (beanType != null) {
			InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
			metadata.checkConfigMembers(beanDefinition);
		}
	}

4、AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata

	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					try {
						metadata = buildAutowiringMetadata(clazz);
						this.injectionMetadataCache.put(cacheKey, metadata);
					}
					catch (NoClassDefFoundError err) {
						throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
								"] for autowiring metadata: could not find class that it depends on", err);
					}
				}
			}
		}
		return metadata;
	}

顾名思义,这个方法就是找出Autowired注解的元数据,先从缓存中找,开始缓存中肯定是没的,所以会执行buildAutowiringMetadata方法构建出Autowired注解的元数据,然后再放入缓存中。

5、AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata

	private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
		Class<?> targetClass = clazz;

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

			ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
				@Override
				public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
					AnnotationAttributes ann = findAutowiredAnnotation(field);
					if (ann != null) {
						if (Modifier.isStatic(field.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static fields: " + field);
							}
							return;
						}
						boolean required = determineRequiredStatus(ann);
						currElements.add(new AutowiredFieldElement(field, required));
					}
				}
			});

			//这里省略部分源码,和上面的doWithLocalFields是同样的逻辑,
			// 只不过上面是从字段上找标注了Autowired的字段,下面试找标注了Autowired的方法
			ReflectionUtils.doWithLocalMethods(...);

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return new InjectionMetadata(clazz, elements);
	}

这里遍历类中的所有字段,找出标注了@Autowired注解的字段,然后先添加到currElements 这个集合中,通过源码可以看到,这个currElements是InjectionMetadata.InjectedElement类型的,InjectedElement呢主要就是记录一下字段的完整类型和这个字段在哪个类中,比如我们有如下代码

@Service
public class MuService {
	@Autowired
	private CalculateFeeEngine[] calculateFeeEngines;
}

那这个currElements 就像下面这样。

image.png
最后,将currElements合并到elements中,并封装成InjectionMetadata类型返回。

拿到了标注了@Autowired注解的字段信息后,再回到开头提到的第二处方法。populateBean(beanName, mbd, instanceWrapper);进行属性的填充。属性填充这里也会执行后置处理器,其中会执行后置处理器的postProcessPropertyValues,这里我们需要去看下面的方法

6、AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

这里先去找注解的元信息,前面分析到,findAutowiringMetadata方法已经被执行了一次了,并且将注解的元信息已经放到了缓存里,所以这里就直接从缓存中拿到了。 拿到注解元数据后,就开始执行inject方法了。

7、InjectionMetadata#inject

	public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> elementsToIterate =
				(this.checkedElements != null ? this.checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			boolean debug = logger.isDebugEnabled();
			for (InjectedElement element : elementsToIterate) {
				if (debug) {
					logger.debug("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}

这里先从checkedElements 或者injectedElements赋给elementsToIterate,这个是什么呢?就是上文提到的截图那样。然后遍历每个InjectedElement,执行inject方法。

8、AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

这个方法里面主要是下面这个方法

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

然后执行下面的方法

9、DefaultListableBeanFactory#doResolveDependency

	public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
			Set<String> autowiredBeanNames, 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) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(type, 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);
			}
			return (instanceCandidate instanceof Class ?
					descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

resolveMultipleBeans方法如下:

9.1 DefaultListableBeanFactory#resolveMultipleBeans

	private Object resolveMultipleBeans(DependencyDescriptor descriptor, String beanName,
			Set<String> autowiredBeanNames, TypeConverter typeConverter) {

		Class<?> type = descriptor.getDependencyType();
		if (type.isArray()) {
			Class<?> componentType = type.getComponentType();
			ResolvableType resolvableType = descriptor.getResolvableType();
			Class<?> resolvedArrayType = resolvableType.resolve();
			if (resolvedArrayType != null && resolvedArrayType != type) {
				type = resolvedArrayType;
				componentType = resolvableType.getComponentType().resolve();
			}
			if (componentType == null) {
				return null;
			}
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof Object[]) {
				Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
			Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
			if (elementType == null) {
				return null;
			}
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof List) {
				Collections.sort((List<?>) result, adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		else if (Map.class == type) {
			ResolvableType mapType = descriptor.getResolvableType().asMap();
			Class<?> keyType = mapType.resolveGeneric(0);
			if (String.class != keyType) {
				return null;
			}
			Class<?> valueType = mapType.resolveGeneric(1);
			if (valueType == null) {
				return null;
			}
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			return matchingBeans;
		}
		else {
			return null;
		}
	}

这个方法里面根据字段的类型,执行对应的分支,上面的示例我们的字段类型不是数组嘛,所以这里就直接执行第一个分支,使用findAutowireCandidates方法找出满足类型的所有类装载到这个数组中。 从源码可以看到,这个方法里面是给数组,集合的接口,Map这三种类型装载类的,如果添加了@Autowired注解的字段不是这三个中的,那就会直接返回null。

resolveMultipleBeans执行完如果返回的数据不为null,那就会继续返回结果退出doResolveDependency方法。如果是null,就要执行findAutowireCandidates方法再次获取需要注入的值,什么时候需要靠下面这个方法获取注入的值呢?就是字段的类型不是数组,不是集合,不是Map,就是单个对象的时候。 那如果是注入单个的对象,这里可能就会有问题了,通过findAutowireCandidates找出的注入的bean可能会超过一个,那这个时候就需要把找出的多个bean进行筛选,这个时候就需要determineAutowireCandidate来决定使用哪个。

9.2 DefaultListableBeanFactory#determineAutowireCandidate

	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能不能决定出一个,再看看根据优先级能不能决定一个。如果都不行,那就根据字段的名字匹配出一个。如果还是不能决定出,那就返回null。 向上一级返回null后(到达 9、DefaultListableBeanFactory#doResolveDependency),如果说这个字段的引入是必须的,那就会通过代码

 return descriptor.resolveNotUnique(type, matchingBeans);

抛出常见的异常:“xxxxxxx expected single matching bean but found xxxxxxx” 执行完上面的流程,如果能正常拿到值后,就把拿到的值设置到对应的字段上去。至此, @Autowired解析完毕。