本文基于 Spring Boot 3.0.0 (Spring 6.0.2)。
@Autowired
来自于 spring-beans 模块;而@Resource
则来自于 jakarta.annotation-api 模块,它是 Jakarta EE 规范中的内容。虽然 @Autowired 与 @Resource 均用于实现依赖注入,但 Spring 对二者的处理逻辑是不一样的。
面向 @Autowired 与 @Resource 注解的依赖注入发生于 Bean 加载流程中 属性填充 populateBean 阶段,具体逻辑位于InstantiationAwareBeanPostProcessor
实现类的postProcessProperties() 方法内。InstantiationAwareBeanPostProcessor 主要有两个实现类,分别是:AutowiredAnnotationBeanPostProcessor
和CommonAnnotationBeanPostProcessor
。
CommonAnnotationBeanPostProcessor 优先于 AutowiredAnnotationBeanPostProcessor 执行,因此咱们先来分析 @Resource 注解,然后是 @Autowired 注解。
在 CommonAnnotationBeanPostProcessor 中,postProcessProperties() 方法负责为 Bean 实例内由 @Resource 注解标识的 成员变量、setter 方法 注入依赖。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
}
从上述内容来看,postProcessProperties() 方法做了两件事。
InjectionMetadata
实例,该实例内封装了若干ResourceElement
,而每个 ResourceElement 实例代表了一个由 @Resource 注解标识的 字段 或 setter 方法。inject()
方法完成依赖注入。接着跟进到 InjectionMetadata 中的 inject() 方法,主要就是遍历 ResourceElement 并调用其 inject() 方法。
public class InjectionMetadata {
public void inject(Object target, String beanName, 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);
}
}
}
}
ResourceElement 继承自LookupElement
,LookupElement 又继承自InjectedElement
;从 InjectionMetadata 中 inject() 方法可以看出一些端倪:InjectedElement 肯定抽象了整体的注入逻辑,留一些拓展给子类覆盖,这是老套路了。
继续跟进到 InjectedElement 中的 inject() 方法。
public abstract static class InjectedElement {
protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
} else {
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return null;
}
}
没错,InjectedElement 最终是通过反射机制来实现依赖注入的。getResourceToInject()
方法用于获取所需要的依赖,InjectedElement 并没有为该方法提供具体的实现,需要由其子类来覆盖。关于 InjectedElement 的继承关系如下图所示。
现在!是时候到 ResourceElement 中一探究竟了。
private class ResourceElement extends LookupElement {
private final boolean lazyLookup;
public ResourceElement(Member member, AnnotatedElement ae, PropertyDescriptor pd) {
super(member, pd);
Resource resource = ae.getAnnotation(Resource.class);
String resourceName = resource.name();
Class<?> resourceType = resource.type();
this.isDefaultName = !StringUtils.hasLength(resourceName);
if (this.isDefaultName) {
resourceName = this.member.getName();
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
resourceName = StringUtils.uncapitalizeAsProperty(resourceName.substring(3));
}
} else if (embeddedValueResolver != null) {
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
if (Object.class != resourceType) {
checkResourceType(resourceType);
} else {
// No resource type specified... check field/method.
resourceType = getResourceType();
}
this.name = (resourceName != null ? resourceName : "");
this.lookupType = resourceType;
String lookupValue = resource.lookup();
this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
}
ResourceElement 构造方法内有两处逻辑值得大家关注:
isDefaultName
属性值为 true,进一步表明 ResourceElement 实例中name
属性值要么是成员变量名称,亦或是转换后的 setter 方法名称,具体是通过 StringUtils.uncapitalizeAsProperty(resourceName.substring(3)) 转换的;另外,我们还看到了EmbeddedValueResolver
的身影,这意味着 @Resource 注解的 name 属性值是可以使用占位符的。lookupType
属性值要么是成员变量所对应的 Class,亦或是 setter 方法参数所对应的 Class;如果 @Resource 注解的 type 属性值非默认值,则 ResourceElement 实例中lookupType
属性值直接就是 Resource 注解中 type 属性所指定的了。此外,ResourceElement 中的 getResourceToInject() 方法具体会委派 CommonAnnotationBeanPostProcessor 的 getResource() 方法来获取具体的依赖。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
protected Object getResource(LookupElement element, String requestingBeanName) throws NoSuchBeanDefinitionException {
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName) throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory autowireCapableBeanFactory) {
// new LookupDependencyDescriptor((Field) this.member, this.lookupType)
// or
// new LookupDependencyDescriptor((Method) this.member, this.lookupType)
DependencyDescriptor descriptor = element.getDependencyDescriptor();
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
// 核心逻辑
resource = autowireCapableBeanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
} else {
// 核心逻辑
resource = autowireCapableBeanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
} else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory configurableBeanFactory) {
for (String autowiredBeanName : autowiredBeanNames) {
if (requestingBeanName != null && configurableBeanFactory.containsBean(autowiredBeanName)) {
configurableBeanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
}
上述 autowireResource() 方法交代了两个极为重要的知识点:
isDefaultName
属性值为 true 且 ResourceElement 实例的name
属性值在一级缓存 singletonObjects 以及 beanDefinitionMap 中不存在,那么通过 AutowireCapableBeanFactory 的resolveDependency()
方法来获取依赖。这说明需要根据 ResourceElement 实例中的 lookupType 来加载所需依赖 ,因为根据 name 来完成依赖的加载是不可能的了。isDefaultName
属性值为 true,且 ResourceElement 实例的name
属性值在一级缓存 singletonObjects 以及 beanDefinitionMap 中存在;或者当前 ResourceElement 实例的isDefaultName
属性值为 false,那么则委派 AutowireCapableBeanFactory 的resolveBeanByName()
方法来拿到所需的依赖。这说明直接根据 ResourceElement 实例中的 name 来获取所需依赖即可 。下面分小节对 AutowireCapableBeanFactory 中的 resolveDependency() 方法与 resolveBeanByName() 方法进行分析。
resolveDependency() 方法具体会委派doResolveDependency()
方法去干活。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// descriptor 实际为 LookupDependencyDescriptor 类型
// descriptor.getDependencyType() 就是 ResourceElement 实例中的 lookupType
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String strValue) {
String resolvedValue = resolveEmbeddedValue(strValue);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(resolvedValue, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
} catch (UnsupportedOperationException ex) {
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// lookupType 如果为 Array、Collection 或 Map
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// lookupType 为简单的引用类型,执行到这里说明所需要的依赖是单个 Bean,不会是集合之类的
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 如果根据 lookupType 获取到多个依赖 Bean,那么需要根据 @Primary 和 @Priority 过滤
// 确保最终只有一个依赖 Bean
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
} else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
} else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
} finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
}
敲黑板!!!从上述内容来看,doResolveDependency() 方法极度依赖一个方法,它就是findAutowireCandidates()
。findAutowireCandidates() 方法是干嘛的呢?它可以根据Class<?>
类型的参数 requiredType 来匹配出所有的 beanName,然后通过 beanName 来加载 Bean 实例,最后封装为一个Map<String, Object>
类型的结果;在该 Map 中,key 为 beanName、value 为 Bean 实例。至于 findAutowireCandidates() 的内容,需要大家自行去阅读源码了。
如何根据
Class<?>
类型的参数 requiredType 来匹配出所有的 beanName ?
String[] candidateNames
= BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
根据 requiredType 只是匹配到所有的 beanName,还不是 Bean 实例,那么 Bean 实例是如何加载出来的?
public class DependencyDescriptor extends InjectionPoint implements Serializable {
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
}
可见,resolveDependency() 方法先是根据 lookupType 来拿到所需要的依赖名称,然后根据名称加载出真正的依赖。
相较于 resolveDependency() 方法,resolveBeanByName() 逻辑可就直白多了,直接根据 ResourceElement 实例中的 name 来加载 Bean。
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@Override
public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// descriptor 实际为 LookupDependencyDescriptor 类型
// descriptor.getDependencyType() 就是 ResourceElement 实例中的 lookupType
// name 就是 ResourceElement 实例中的 name
return getBean(name, descriptor.getDependencyType());
} finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
}
在开始加载由 @Resource 注解标识的依赖之前,会先走
factory.containsBean(name)
这个逻辑,以决定究竟是基于 byType 策略,还是基于 byName 策略去加载特定依赖。如果 factory.containsBean(name) 为 true,那肯定可以根据 name 加载出所需的依赖,这样最省事,否则不得不根据 type 来加载了。正因为是先走了 factory.containsBean(name) 这一逻辑,所以说 @Resource 注解是优先基于 byName 策略来加载依赖,然后才是 byType 策略!
在 AutowiredAnnotationBeanPostProcessor 中,postProcessProperties() 方法负责为 Bean 实例内由 @Autowired 注解标识的 成员变量、setter 方法 和 构造方法 注入依赖。
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, BeanRegistrationAotProcessor, PriorityOrdered, BeanFactoryAware {
@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;
}
}
InjectionMetadata 在第一章节已经介绍过,这里直接去 AutowiredElement 中找 getResourceToInject() 方法。在 AutowiredElement 的两个实现类AutowiredFieldElement
、AutowiredMethodElement
中并没有发现 getResourceToInject() 方法的身影,因为它俩直接覆盖了 inject() 方法。本文这里选取更为常用的 AutowiredFieldElement 作为分析目标。
private class AutowiredFieldElement extends AutowiredAnnotationBeanPostProcessor.AutowiredElement {
public AutowiredFieldElement(Field field, boolean required) {
super(field, null, required);
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value = resolveFieldValue(field, bean, beanName);
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
return value;
}
}
在 AutowiredFieldElement 内,resolveFieldValue() 方法承担了加载依赖的重任,其内部实现依然是委托 resolveDependency() 方法,这个方法在上一章节已经介绍过了。
@Resource 注解是优先基于 byType 策略来加载出依赖的名称,然后基于 byName 策略来加载出真正的依赖!
建议大家自行阅读 resolveDependency() 方法内关于 泛型 Bean 的注入逻辑。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有