零、前言
@Autowired
和@Resource
注解都可以在Spring应用中进行声明式的依赖注入。以前都是看的网上关于两者的区别,但是实际和网上说的有出入,故从源码角度进行分析、验证。
以下源码基于spring 5.3.20(通过springboot 2.7.0引入)
一、结论
1、@Autowired注解总结
- 可用于构造函数,成员变量以及set方法
- 从Spring 4.3开始,如果目标Bean只有一个构造函数,则在该构造函数上可以省略
@Autowired
注解;如果目标Bean有多个构造函数则不可省略
@Autowired
注入方式:
- 按照type查找bean,如果使用
@Qualifier
注解声明了name,则从结果集中取出与该name相匹配的bean返回(此时可以视为通过name和type获取bean,但实质是先通过type获取所有bean,然后通过name筛选,详情见后文findAutowireCandidates()
方法源码分析) - 如果没有使用
@Qualifier
注解,且找到多个bean,则判断这些bean中是否有使用@Primary注解和@Priority注解,有就返回优先级最高的哪一个bean,没有就按照字段名称去匹配bean,匹配成功返回,不成功抛出异常。(详情见后文determineAutowireCandidate()
方法源码解析)
整体注入流程如下所示:
2、@Resource注解总结
-
可用于成员变量以及set方法
-
若不指定name属性,则会把name属性值处理为字段名或set方法标识的字段名
-
若指定type属性,则type属性值必须与字段类型或set方法返回值类型为父子关系(type属性值可以是子类,也可以是超类),否则会抛出异常
-
@Resource
先按照name属性值注入,若未找到,则按type属性值注入。即默认的name或指定的name找不到 bean ,就会按type注入
整体注入流程如下所示:
二、@Autowired注入过程源码分析
1、AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata():切入点
首先定位到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata()
方法,代码如下。可以看到,如果是在属性上声明@Autowired
,则构造AutowiredFieldElement
对象,如果是在方法上声明@Autowired
,则构造AutowiredMethodElement
对象。
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> 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);
// 构造AutowiredFieldElement对象
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);
// 构造AutowiredMethodElement对象
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);
}
AutowiredFieldElement
和AutowiredMethodElement
对象很类似,都是构造器初始化数据,inject()
获取bean,现以AutowiredFieldElement
为例进行说明。
2、AutowiredFieldElement对象
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
private final boolean required;
private volatile boolean cached;
@Nullable
private volatile Object cachedFieldValue;
// 1、构造器初始化数据,由于@Autowired就一个required属性,故非常见到那
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
// 2、inject()方法获取bean
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws