@AutoWired注解原理探索

一、引言:

我们经常在代码中通过@AutoWired注解给属性、方法参数、构造方法等注入其他bean实例,使用非常方便,于是就想探索下其实现原理。

不妨假设如果是我们自己来实现这个注解,该怎样去实现了(这里只以注解标识过的字段属性为例,其他的方法参数、构造方法等都类似):

  1. 定义注解(这个注解只有一个required属性);
  2. 我们知道Spring在启动时会加载所有bean到容器,每个bean在实例化后需要遍历其所有标识了@AutoWires注解的属性,根据其类型,在bean容器中查找该类型的bean,并赋值给该属性。Spring在每个bean实例化后会调用PopularBean来处理属性值,后置处理器BeanPostProcessor正适合处理这类问题。在Spring中有一个扩展接口InstantiationAwareBeanPostProcessor继承自BeanPostProcessor,定义了方法postProcessPropertyValues,我们可以定义一个实现了接口InstantiationAwareBeanPostProcessor的类,在其postProcessPropertyValues方法中处理@AutoWired标识过的属性赋值。

事实上Spring对于AutoWired注解的处理跟我们的思路也是差不多的,首先在MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition中查找bean定义中所有加了@AutoWired注解的属性并缓存到InjectionMetadata类型的变量metadata中,然后在InstantiationAwareBeanPostProcessor.postProcessPropertyValues中注入bean属性。接下来我们通过SpringBoot源码来分析下@AutoWired注解在SpringBoot中是如何实现的。

二、@AutoWired注解的定义:

less 复制代码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
	boolean required() default true;
}

三、@AutoWired注解的属性加载:

1、SpringBoot应用在启动时会创建一个实现了ApplicationContext接口的对象,类型是AnnotationConfigServletWebServerApplicationContext,从GenericApplicationContext继承过来的,在GenericApplicationContext的构造方法中创建了DefaultListableBeanFactory,如下:

/ 复制代码
public GenericApplicationContext() {
	this.beanFactory = new DefaultListableBeanFactory();
}

DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory。创建bean时调用的是createBean,createBean又调用doCreateBean,doCreateBean又调用后置处理器applyMergedBeanDefinitionPostProcessors:

scss 复制代码
//AbstractAutowireCapableBeanFactory.java

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	//.........省略部分代码,只贴出关键代码..........
	RootBeanDefinition mbdToUse = mbd;
	mbdToUse.prepareMethodOverrides();
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	//调用doCreateBean
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	return beanInstance;
}

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
	//.........省略部分代码,只贴出关键代码..........
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	//重点:这里调用后置处理器
	applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	populateBean(beanName, mbd, instanceWrapper);
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	registerDisposableBeanIfNecessary(beanName, bean, mbd);
	return exposedObject;
}

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof MergedBeanDefinitionPostProcessor) {
			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
			//AutoWired注解会调用到AutowiredAnnotationBeanPostProcessor上
			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}
}

applyMergedBeanDefinitionPostProcessors方法会遍历出所有的MergedBeanDefinitionPostProcessor并分别调用,对于处理AutoWired注解的后置处理器类为AutowiredAnnotationBeanPostProcessor,下面进入AutowiredAnnotationBeanPostProcessor的处理方法:

typescript 复制代码
//AutowiredAnnotationBeanPostProcessor.java

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

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	//.........省略部分代码,只贴出关键代码..........
	metadata = buildAutowiringMetadata(clazz);
	return metadata;
}

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
	//.........省略部分代码,只贴出关键代码..........
	LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
	Class<?> targetClass = clazz;

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

		//通过反射ReflectionUtils.doWithLocalFields遍历类的所有字段
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			//查找字段上定义的AutoWired和Value注解的属性值集合
			AnnotationAttributes ann = findAutowiredAnnotation(field);
			if (ann != null) {				
				boolean required = determineRequiredStatus(ann);
				//缓存AutoWired和Value注解的属性值集合到currElements
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});
		elements.addAll(0, currElements);
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);

	缓存AutoWired和Value注解的属性值集合到InjectionMetadata类中
	return new InjectionMetadata(clazz, elements);
}

buildAutowiringMetadata遍历类的所有字段,findAutowiredAnnotation查找字段上定义的AutoWired和Value注解的属性值集合并缓存到currElements,最后缓存到InjectionMetadata类中。findAutowiredAnnotation的定义如下:

csharp 复制代码
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
	if (ao.getAnnotations().length > 0) {
		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
			AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
			if (attributes != null) {
				return attributes;
			}
		}
	}
	return null;
}

public AutowiredAnnotationBeanPostProcessor() {
	this.autowiredAnnotationTypes.add(Autowired.class);
	this.autowiredAnnotationTypes.add(Value.class);
	//.........省略部分代码.........
}

至此@AutoWired注解的属性加载到InjectionMetadata类中就完成了。

四、属性注入:

在AbstractAutowireCapableBeanFactory.doCreateBean会调用populateBean,我们进入populateBean看看实现:

scss 复制代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	//.........省略部分代码,只贴出关键代码..........
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName);
		}
	}
	
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
		
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}

		pvs = newPvs;
	}
	
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			//重点,这里处理bean的注入
			ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);			
		}
	}
	if (needsDepCheck) {
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}

ibp.postProcessPropertyValues会处理AutoWired注解的bean属性赋值,这里处理AutoWired注解的InstantiationAwareBeanPostProcessor是AutowiredAnnotationBeanPostProcessor。

ini 复制代码
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	metadata.inject(bean, beanName, pvs);
	return pvs;
}

这里的findAutowiringMetadata会先缓存,查到则直接返回,查不到就调用buildAutowiringMetadata重新构造InjectionMetadata实例返回。由于在上一步中已经构造InjectionMetadata实例并缓存,因此会直接返回InjectionMetadata实例。接着就调用其inject方法完成注入:

less 复制代码
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) {
        	//重点
			element.inject(target, beanName, pvs);
		}
	}
}

InjectedElement的实现类有AutowiredFieldElement和AutowiredMethodElement,由于我们只看字段属性,因此就进入AutowiredFieldElement看看:

less 复制代码
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	//.........省略部分代码,只贴出关键代码..........
	Field field = (Field) this.member;
	DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
	desc.setContainingClass(bean.getClass());
	Set<String> autowiredBeanNames = new LinkedHashSet<>(1);	
	TypeConverter typeConverter = beanFactory.getTypeConverter();
	//从Spring容器中解析出AutoWired的属性值
	value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
	//.........省略部分代码,只贴出关键代码..........
	result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
	return result;	
}

inject方法注入bean到属性值,beanFactory.resolveDependency返回AutoWired标注的bean对象,最后通过field.set(bean, value)将value设置给AutoWired标注的字段。

下面来看看doResolveDependency是如何找出bean对象的:

typescript 复制代码
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) {
    //.........省略部分代码,只贴出关键代码..........
	Class<?> type = descriptor.getDependencyType();
	//在容器中查找出类型为type的所有beanName和其对应的class
	Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
	
	String autowiredBeanName;
	Object instanceCandidate;
	if (matchingBeans.size() > 1) {
		//如果查找到的bean不止一个,则采用一定的策略确定最终使用的那个bean
		autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);			
		instanceCandidate = matchingBeans.get(autowiredBeanName);
	}
	else {	
		//如果只有一个bean,就是他了
		Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
		autowiredBeanName = entry.getKey();
		instanceCandidate = entry.getValue();
	}

	autowiredBeanNames.add(autowiredBeanName);
	if (instanceCandidate instanceof Class) {
		//根据bean的名称在容器中查找到bean对象
		instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
	}
	//将确定的唯一bean对象返回
	Object result = instanceCandidate;	
	return result;
}

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
    //.........省略部分代码,只贴出关键代码..........
	return beanFactory.getBean(beanName);
}

doResolveDependency中,首先在容器中查找出类型为type的所有beanName和其对应的class,保存到变量matchingBeans中,这些bean都符合AutoWired的要求,如果matchingBeans中只有一个元素,那么毫无疑问就是他了,如果有多个怎么办,通过determineAutowireCandidate方法来确定那唯一的bean。

matchingBeans中存储的是beanName和beanClass的键值对,注意不是bean实体对象,所以嗨需要通过descriptor.resolveCandidate来将Class转换为bean对象,可以看到在descriptor.resolveCandidate中通过beanFactory.getBean直接在Spring容器中根据beanName查找到bean对象.

下面看看findAutowireCandidates是如何根据Type确定所有候选的bean的:

typescript 复制代码
protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
    //.........省略部分代码,只贴出关键代码..........
	//查找出所有符合requiredType的beanNames
	String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
			this, requiredType, true, descriptor.isEager());
	Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
	for (String candidate : candidateNames) {
		if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
			//将beanName和其对应的class添加到map对象result中
			addCandidateEntry(result, candidate, descriptor, requiredType);
		}
	}
	return result;
}

private void addCandidateEntry(Map<String, Object> candidates, String candidateName, DependencyDescriptor descriptor, Class<?> requiredType) {
    //.........省略部分代码,只贴出关键代码..........
	candidates.put(candidateName, getType(candidateName));
}

public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
    //.........省略部分代码,只贴出关键代码..........
	String beanName = transformedBeanName(name);
	RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
	//predictBeanType取得beanName的Class
	Class<?> beanClass = predictBeanType(beanName, mbd);
	return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
}

protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
    //.........省略部分代码,只贴出关键代码..........
	Class<?> targetType = mbd.getTargetType();
	if (targetType != null) {
		return targetType;
	}
	//........省略部分代码...........
}

首先根据BeanFactoryUtils.beanNamesForTypeIncludingAncestors确定所有候选beanNames,然后遍历循环beanNames,计算每个beanName的class并添加到map中返回,在根据beanName确定Class时调用的是RootBeanDefinition.getTargetType()来确定的。

在doResolveDependency中,如果候选bean有多个的话,通过determineAutowireCandidate来确定那个唯一,我们来看看这个唯一是依据什么原则来确定的:

typescript 复制代码
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;
}

从上面的实现可以看到,首先看看这个bean上有没有primary注解,有的话他就是这个唯一了,如果没有就看bean上有没有priority注解,有的话就选择优先级最高的那个bean,如果都没有的话则通过matchesBeanName来根据名称来匹配这个唯一了。如果都不符合的话就返回空,在方法调用外层会判断如果是空则抛出NoUniqueBeanDefinitionException类型的异常。

五、Resource注解:

从上面@AutoWired注解的解析可以看到,@Value注解的解析是跟@AutoWired注解的解析在一起的。

@Resource注解的流程跟AutoWired注解的流程一摸一样,只是其后置处理器换成了CommonAnnotationBeanPostProcessor,且所有之前查找AutoWired的地方全部换成了Resource,比如如下代码:

less 复制代码
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    //.........省略部分代码,只贴出关键代码..........
	super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
	//这里换成了findResourceMetadata
	InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
	metadata.checkConfigMembers(beanDefinition);
}

private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
    //.........省略部分代码,只贴出关键代码..........
	metadata = buildResourceMetadata(clazz);
	return metadata;	
}

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    //.........省略部分代码,只贴出关键代码..........
	LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
	Class<?> targetClass = clazz;

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

		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			if (!ignoredResourceTypes.contains(field.getType().getName())) {
				currElements.add(new ResourceElement(field, field, null));
			}
		});

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

	return new InjectionMetadata(clazz, elements);
}

public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
    //.........省略部分代码,只贴出关键代码..........
	//这里换成findResourceMetadata
	InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
	metadata.inject(bean, beanName, pvs);
	return pvs;
}

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) {
    //.........省略部分代码,只贴出关键代码..........
	Field field = (Field) this.member;
	ReflectionUtils.makeAccessible(field);
	//换成getResourceToInject
	field.set(target, getResourceToInject(target, requestingBeanName));
}

protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
    //.........省略部分代码,只贴出关键代码..........
	return getResource(this, requestingBeanName);
}

protected Object getResource(LookupElement element, @Nullable String requestingBeanName) {
    //.........省略部分代码,只贴出关键代码..........
	return autowireResource(this.resourceFactory, element, requestingBeanName);
}

protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) {
    //.........省略部分代码,只贴出关键代码..........
	resource = factory.getBean(name, element.lookupType);
	autowiredBeanNames = Collections.singleton(name);
	return resource;
}

从autowireResource方法的实现中可以看到,factory.getBean(name, element.lookupType)是首先依据名称来查找的。

相关推荐
Albert Edison3 小时前
【最新版】IntelliJ IDEA 2025 创建 SpringBoot 项目
java·spring boot·intellij-idea
Piper蛋窝4 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
六毛的毛6 小时前
Springboot开发常见注解一览
java·spring boot·后端
AntBlack6 小时前
拖了五个月 ,不当韭菜体验版算是正式发布了
前端·后端·python
31535669136 小时前
一个简单的脚本,让pdf开启夜间模式
前端·后端
uzong6 小时前
curl案例讲解
后端
开开心心就好7 小时前
免费PDF处理软件,支持多种操作
运维·服务器·前端·spring boot·智能手机·pdf·电脑
一只叫煤球的猫7 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
猴哥源码7 小时前
基于Java+SpringBoot的农事管理系统
java·spring boot
大鸡腿同学8 小时前
身弱武修法:玄之又玄,奇妙之门
后端