一、引言:
我们经常在代码中通过@AutoWired注解给属性、方法参数、构造方法等注入其他bean实例,使用非常方便,于是就想探索下其实现原理。
不妨假设如果是我们自己来实现这个注解,该怎样去实现了(这里只以注解标识过的字段属性为例,其他的方法参数、构造方法等都类似):
- 定义注解(这个注解只有一个required属性);
- 我们知道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)是首先依据名称来查找的。