先看一个案例
package com.example.demo.car;
public interface Engine {
void run();
}
@Component
public class BMWEngine implements Engine {
@Override
public void run() {
System.out.println("BMWEngine running");
}
}
@Component
public class MazdaEngine {
}
我们只定义一个Engine实现类BMWEngine,对于需要自动注入的类
@Component
public class CarA {
// 1. @Autowired 按类型注入,配合 @Qualifier 按名称
@Autowired
private Engine mazdaEngine;
}
@Component
public class CarB {
// 2. @Resource 默认按名称注入
@Resource
private Engine mazdaEngine;
}
看起来两个除了注解不一样(@Resource 和 @Autowired)其他都一样, 只有一个Engine 实现类,能正确注入。
但是 CarA 在找不到mazdaEngine名称的Engine实现类会@Autowired根据类型找到BMWEngine,而CarB则根据mazdaEngine找到了对应的类但发现类型不一致抛了异常
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'mazdaEngine' is expected to be of type 'com.example.demo.car.Engine' but was actually of type 'com.example.demo.car.MazdaEngine'
at org.springframework.beans.factory.support.AbstractBeanFactory.adaptBeanInstance(AbstractBeanFactory.java:417)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:398)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:479)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:520)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:673)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:228)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:329)
... 12 more
具体在spring源码如何处理这两个注解的?
首先看下 spring 的初始化流程
你可能疑问,这B咋还不引入正题,其实这两个注解是初始化流程的一部分,是不能脱离初始化过程来弹得
每个 Spring 类会放在 BeanDefinition 中,BeanDefinition 包含初始化对象的相关信息,如有所属类、class、ID、factory method、factory class、scope(单例or原型) 等属性。BeanDefinition 一般放置在 Map 中,即 BeanDefinitionMap,在一个 Spring 进程中只有一份。
Spring初始化时会按beanDefinitionMap循环调用初始化方法,该方法在BeanFactory.getBean中。BeanFactory.getBean会先在singletonOobjectsMap(也是一个map,key是类名,value是具体实例对象)中查找,若找不到则执行bean初始化过程。初始化这些对象时会递归调用BeanFactory.getBean,此时会有循环依赖问题,Spring通过三级缓存处理。对象初始化完才会放到singletonObjectMap中。通过ApplicationContext来获取的getBean其实本身也是通过BeanFactory.getBean,只是做了一层门面。
org.springframework.context.annotation.AnnotationConfigApplicationContext 实际使用的 org.springframework.beans.factory.support.DefaultListableBeanFactory
以下是创建bean的流程
populateBean处理需要依赖注入的属性,解析 @Resource 或 @Autowire的注解
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 1. 实例化 bean
Object beanInstance = createBeanInstance(beanName, mbd, args);
// 2. 处理循环依赖(提前暴露 bean)
if (allowCircularReferences) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));
}
// 3. 填充属性(依赖注入)
populateBean(beanName, mbd, instanceWrapper);
// 4. 初始化 bean
Object exposedObject = initializeBean(beanName, beanInstance, mbd);
// 5. AOP 代理处理
// 6. 注册销毁回调
return exposedObject;
}
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 1. 检查 bean 是否已实例化
if (bw == null) return;
// 2. 处理 InstantiationAwareBeanPostProcessor
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessors()) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return; // 跳过后续属性注入
}
}
// 3. 获取属性值
PropertyValues pvs = mbd.getPropertyValues();
// 4. 允许后置处理器修改属性值(如处理@Autowired、@Resource等)
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessors()) {
pvs = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 兼容老接口
if (pvs == null) {
pvs = bp.postProcessPropertyValues(pvs, bw.getPropertyDescriptors(), bw.getWrappedInstance(), beanName);
}
}
// 5. 应用属性值(依赖注入)
applyPropertyValues(beanName, mbd, bw, pvs);
}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 1. 处理 Aware 接口
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
// 2. BeanPostProcessor 前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 3. 调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
// 4. BeanPostProcessor 后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
// 5. 返回
return wrappedBean;
}
}
在看看注解处理器具体代码
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
都实现了 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
postProcessPropertyValues 是Deprecated的,剩下两个方法是从BeanPostProcessor继承的直接空实现了,现在只要看两个类的 postProcessProperties 实现有什么不同就可以了
这里写的比较简略,只标注了差异部分,小伙伴可以直接打开spring源码看
Autowire
AutowiredAnnotationBeanPostProcessor最终调用到DefaultListableBeanFactory的resolveDependency, findAutowireCandidates 会根据类型找到符合的Bean,如果有多个再根据名称筛一遍
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 省略
// 1. 查找所有候选bean(按类型、限定符等)
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// 5. 没有找到候选bean,且依赖是必须的,抛出异常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
// 省略
String autowiredBeanName;
Object instanceCandidate;
// 省略
if (matchingBeans.size() > 1) {
// 有多个候选bean,优先选择@Primary/@Priority或名称匹配的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();
}
// 省略
Object result = instanceCandidate;
return result;
}
}
Resource
CommonAnnotationBeanPostProcessor 最后调用到AbstractAutowireCapableBeanFactory.getBean, 如果找到对应名称的类不符合要求的类型会报错 BeanNotOfRequiredTypeException
public abstract class AbstractAutowireCapableBeanFactory
@Override
public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
return getBean(name, descriptor.getDependencyType());
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
}
结论
@Resource 和 @Autowire 均用于 Java 中 Spring 的自动注入 IOC。它们的区别在于来源不同,Resource 是 JavaEE 中的,Autowire 是 Spring 框架中的。Resource 主要先根据名称,再根据类型。若名称匹配但类型与接受类型不兼容则会报错, 若名称不匹配且找不到才会根据类型,此时若有对应类型才会匹配。Autowire 则先根据类型再根据名称,当类型匹配多个时才会去找名称,且名称要与 Spring 注册的类匹配。若名称与具体类不同,可加上 Qualifier 注解指定要匹配的类,即它们注入类的查找方式不同。