@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)是首先依据名称来查找的。

相关推荐
小蒜学长13 分钟前
基于Spring Boot的宠物领养系统的设计与实现(代码+数据库+LW)
java·前端·数据库·spring boot·后端·旅游·宠物
GraduationDesign1 小时前
基于SpringBoot的在线文档管理系统的设计与实现
java·spring boot·后端
xiaosannihaiyl242 小时前
Scala语言的函数实现
开发语言·后端·golang
墨鸦_Cormorant2 小时前
JDK 8 升级 17 及 springboot 2.x 升级 3.x 指南
java·spring boot
山山而川粤7 小时前
母婴用品系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
m0_748235078 小时前
SpringBoot集成kafka
spring boot·kafka·linq
玉红77710 小时前
R语言的数据类型
开发语言·后端·golang
呜呼~2251410 小时前
前后端数据交互
java·vue.js·spring boot·前端框架·intellij-idea·交互·css3
lvbu_2024war0111 小时前
MATLAB语言的网络编程
开发语言·后端·golang
问道飞鱼11 小时前
【Springboot知识】Springboot进阶-实现CAS完整流程
java·spring boot·后端·cas