@Autowired 到底是怎么把变量注入进来的?

2023年 7月 14日 75.2k 0

@

文章导航


在 Spring 容器中,当我们想给某一个属性注入值的时候,有多种不同的方式,例如可以通过构造器注入、可以通过 set 方法注入,也可以使用 @Autowired、@Inject、@Resource 等注解注入。

今天松哥就来和小伙伴们聊一聊,@Autowired 到底是如何把数据注入进来的。

@Service
public class AService {
    @Autowired
    BService bService;
}

1. Bean 的创建

这个问题我们就得从 Bean 的创建开始了,本文主要是和小伙伴们聊 @Autowired,所以 Bean 的创建我就不从第一步开始了,咱们直接来看关键的方法,那就是 AbstractAutowireCapableBeanFactory#doCreateBean 方法:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
    //....
	Object exposedObject = bean;
	try {
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	//...
	return exposedObject;
}

在这个方法中,首先会创建原始的 Bean 对象,创建出来之后,会调用一个 populateBean 方法,这个方法就是给 Bean 的各个属性赋值的方法,标注了 @Autowired 注解的属性被自动赋值也是在这个方法中完成的。

2. populateBean

populateBean 方法内容比较多,我们来看一些关键的地方:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
	// state of the bean before properties are set. This can be used, for example,
	// to support styles of field injection.
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
				return;
			}
		}
	}
	//...
	if (hasInstantiationAwareBeanPostProcessors()) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			if (pvsToUse == null) {
				return;
			}
			pvs = pvsToUse;
		}
	}
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
	if (needsDepCheck) {
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}

这里松哥贴出来的是部分关键代码。

首先来看上面有一个 if,这个 if 主要是判断是否需要后置处理器进行处理,如果不需要,那么就直接 return 掉了,默认情况下,这里并不会 return 掉,而是会继续走后面的流程,因为 postProcessAfterInstantiation 方法默认返回 true。

接下来第二个 if 就是比较关键的一个地方了,在这里会遍历所有相关的后置处理器,尝试通过这些处理器去获取到需要的 value。

负责处理 @Autowired 注解的后置处理器是 AutowiredAnnotationBeanPostProcessor,所以现在,我们就来到 AutowiredAnnotationBeanPostProcessor#postProcessProperties 方法了。

3. postProcessProperties

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	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,就这两件事。分别来看。

3.1 findAutowiringMetadata

private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, @Nullable 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);
				}
				metadata = buildAutowiringMetadata(clazz);
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}

这个方法会先尝试从缓存中获取 metadata,如果能够从缓存中获取到,那就直接返回,缓存中没有的话,那么最终会调用到 buildAutowiringMetadata 方法,去重新构建 metadata,并将构建结果存入到缓存中,以备下一次使用。

那么我们来看下 metadata 到底是如何构建出来的。

private InjectionMetadata buildAutowiringMetadata(Class clazz) {
	if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
		return InjectionMetadata.EMPTY;
	}
	List elements = new ArrayList();
	Class targetClass = clazz;
	do {
		final List currElements = new ArrayList();
		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);
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});
		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);
				currElements.add(new AutowiredMethodElement(method, required, pd));
			}
		});
		elements.addAll(0, currElements);
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);
	return InjectionMetadata.forElements(elements, clazz);
}

这个方法比较长,我来和大家说一下核心逻辑。

首先会调用 isCandidateClass 方法判断当前类是否为一个候选类,判断的依据就是 autowiredAnnotationTypes 变量的值,这个变量在该类的构造方法中进行了初始化,大家来看下这个构造方法:

public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论