Spring 的 依赖注入 是 Spring 框架的核心特性之一。它通过容器管理对象之间的依赖关系,实现解耦、可测试性和灵活性。
一、什么是依赖注入?
依赖注入是一种设计模式,其核心思想是:由外部容器来管理对象的创建和依赖关系,而不是在类内部硬编码依赖对象。
例如:
public class UserService {
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
这里 UserService 不自己创建 UserRepository 实例,而是通过构造函数由外部传入,这就是依赖注入。
二、Spring 中的依赖注入方式
Spring 支持以下几种依赖注入方式:
- 构造器注入
- Setter 注入
- 字段注入(@Autowired)
- 方法注入(如 @Bean 方法中调用其他 Bean)
示例:
@Component
class UserRepository {}
@Component
class UserService {
@Autowired // 字段注入
private UserRepository userRepository;
// 构造器注入
public UserService(@Autowired UserRepository userRepository) {
this.userRepository = userRepository;
}
// Setter 注入
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
三、Spring 依赖注入的核心组件
Spring 容器完成依赖注入的关键类包括:
| 类名 | 功能 |
|---|---|
BeanFactory | Spring IoC 容器的基础接口 |
ApplicationContext | 扩展了 BeanFactory,提供更多企业级功能 |
BeanDefinition | 描述一个 Bean 的元信息(如类名、作用域等) |
BeanPostProcessor | 可以对 Bean 创建前后进行干预 |
InstantiationStrategy | 负责 Bean 的实例化策略 |
AutowiredAnnotationBeanPostProcessor | 处理 @Autowired 等注解 |
四、Spring 依赖注入流程
1. 加载配置(XML 或注解)
- 通过
@ComponentScan扫描包中的组件。 - 读取
@Bean、@Service、@Repository等注解。 - 构建
BeanDefinition对象,注册到BeanDefinitionRegistry。
2. 实例化 Bean
- Spring 使用反射或 CGLIB 创建 Bean 实例。
- 如果是单例,则放入一级缓存(singletonObjects)。
3. 属性填充(依赖注入)
- Spring 解析当前 Bean 需要注入的属性(字段、构造参数、setter)。
- 根据类型或名称查找匹配的 Bean。
- 如果依赖 Bean 尚未创建,则递归创建该 Bean。
4. 初始化 Bean
- 调用
@PostConstruct、InitializingBean接口方法。 - 调用自定义初始化方法(init-method)。
5. 使用 Bean
- Bean 准备就绪,可以被使用。
五、AbstractAutowireCapableBeanFactory
1. populateBean(...) 方法(属性填充)
/**
* 使用 bean 定义中的属性值填充给定的 BeanWrapper 实例。
*
* <p>该方法负责将配置文件(如 XML 或注解)中定义的属性值注入到实际的 Java Bean 对象中。
* 支持自动装配(byName、byType)、后处理器修改属性值、依赖检查等功能。
*
* @param beanName 当前被处理的 Bean 名称,用于日志记录或异常信息
* @param mbd 与当前 Bean 相关的合并后的 BeanDefinition
* @param bw 包装了目标 Bean 实例的 BeanWrapper,用于设置属性值
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果 BeanWrapper 为 null,但有需要设置的属性值,则抛出异常
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName,
"Cannot apply property values to null instance");
} else {
// 没有属性值,跳过属性填充阶段
return;
}
}
// 如果是 Java Record 类型(不可变),则不允许设置属性
if (bw.getWrappedClass().isRecord()) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName,
"Cannot apply property values to a record");
} else {
return; // 跳过对 Record 的属性填充
}
}
// 在设置属性之前,调用所有 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法
// 这个扩展点可以用于字段注入(Field Injection)等场景
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return; // 返回 false 表示跳过后续属性填充
}
}
}
// 获取 BeanDefinition 中的属性值集合
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 处理自动装配模式:根据名称或类型自动注入依赖项
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs); // 根据名称自动装配
}
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs); // 根据类型自动装配
}
pvs = newPvs; // 更新属性值集合
}
// 再次调用 postProcessProperties 方法,允许后处理器进一步修改属性值
if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues(); // 如果为空,重新获取原始属性值
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return; // 返回 null 表示不进行后续操作
}
pvs = pvsToUse; // 替换为处理后的属性值
}
}
// 是否需要执行依赖检查(检查是否所有必须的属性都被正确设置)
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (needsDepCheck) {
// 获取需要检查的属性描述符数组
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs); // 执行依赖检查
}
// 最后,将解析后的属性值应用到目标 Bean 上
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
方法流程
-
空值校验
- 如果
BeanWrapper为null并且有属性值需要设置,则抛出异常。 - 如果是 Java Record 类型,并且有属性值要设置,也抛出异常。
- 如果
-
postProcessAfterInstantiation 后处理器
- 允许
InstantiationAwareBeanPostProcessor修改 Bean 状态,例如AutowiredAnnotationBeanPostProcessor。 - 如果返回
false,直接跳过后续属性填充。
- 允许
-
自动装配逻辑
- 若启用
autowire="byName",调用autowireByName(),根据属性名从容器中查找匹配的 Bean 注入。 - 若启用
autowire="byType",调用autowireByType(),根据属性类型从容器中查找匹配的 Bean 注入。
- 若启用
-
postProcessProperties属性修改- 允许
InstantiationAwareBeanPostProcessor修改最终的属性值列表,例如AutowiredAnnotationBeanPostProcessor。 - 如果返回
null,表示跳过后续操作。
- 允许
-
依赖检查
- 检查是否有未满足的依赖项,比如某些属性没有被赋值。
- 可以选择检查简单属性、对象属性或全部属性。
-
属性值应用
- 调用
applyPropertyValues(...),真正将属性值注入到 Bean 实例中。
- 调用
关键方法
| 方法 | 作用 |
|---|---|
autowireByName(...) | 根据属性名自动装配,查找同名 Bean 注入 |
autowireByType(...) | 根据属性类型自动装配,查找匹配类型的 Bean 注入 |
postProcessProperties(...) | 允许后处理器修改属性值,如 @Autowired、@Resource 注解支持 |
checkDependencies(...) | 检查是否存在未设置的必要属性 |
applyPropertyValues(...) | 将解析后的属性值应用到 Bean 上 |
示例
public class UserService {
private UserRepository userRepository;
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
public class UserRepository {
// ...
}
在配置中使用 autowire="byType":
<bean id="userRepository" class="com.example.UserRepository"/>
<bean id="userService" class="com.example.UserService" autowire="byType"/>
Spring 容器在创建 userService 时会调用 populateBean(...) 方法:
- 发现其属性
userRepository是UserRepository类型; - 自动查找并注入容器中唯一的
UserRepository实例; - 最终通过反射调用
setUserRepository(...)设置属性值。
小结
populateBean(...) 是 Spring 容器实现依赖注入的核心方法之一,它完成了以下关键功能:
- 判断是否需要跳过属性填充(如 Record 类型);
- 提供扩展点让后处理器修改 Bean 状态;
- 支持按名称、按类型自动装配;
- 允许后处理器进一步修改属性值;
- 执行依赖检查;
- 最终将属性值应用到目标 Bean。
2. autowireByName(...) 方法
/**
* 当 autowire 模式设置为 "byName" 时,填充目标 Bean 中未满足的属性值。
* <p>该方法会查找当前 BeanFactory 中与目标 Bean 属性名相同的其他 Bean,
* 并将这些 Bean 注入到对应的属性中。</p>
*
* @param beanName 被装配的目标 Bean 的名称(用于日志或调试信息)
* @param mbd 目标 Bean 的合并后的 BeanDefinition
* @param bw 包装了目标 Bean 实例的 BeanWrapper,用于获取 Bean 的属性信息
* @param pvs 需要注册自动装配结果的 PropertyValues 对象
*/
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取所有未被赋值的、非简单类型的属性名数组(例如:不是基本类型、String 等)
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍历每个未满足的属性名
for (String propertyName : propertyNames) {
// 如果容器中存在同名的 Bean
if (containsBean(propertyName)) {
// 获取该 Bean 实例
Object bean = getBean(propertyName);
// 将该 Bean 添加到属性值集合中,完成自动装配
pvs.add(propertyName, bean);
// 注册依赖关系:propertyName 所属 Bean 依赖于当前 beanName 的 Bean
registerDependentBean(propertyName, beanName);
// 记录日志:按名称装配成功
if (logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
// 如果没有找到匹配的 Bean,则不进行装配,记录日志
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
方法流程
-
获取未满足的非简单属性
- 调用
unsatisfiedNonSimpleProperties(mbd, bw)获取当前 Bean 中未被赋值的、且不是简单类型的属性名数组。
- 调用
-
遍历每个属性
- 对每一个未满足的属性进行处理。
-
检查容器中是否存在同名 Bean
- 使用
containsBean(propertyName)判断是否存在一个名称与属性名相同的 Bean。
- 使用
-
自动装配
- 如果存在,则通过
getBean(propertyName)获取该 Bean; - 将其添加到
pvs中,表示该属性应被自动注入。
- 如果存在,则通过
-
注册依赖关系
- 调用
registerDependentBean(propertyName, beanName),注册两个 Bean 之间的依赖关系。
- 调用
-
日志记录
- 如果启用 trace 日志级别,记录装配过程的信息或失败原因。
registerDependentBean(...)
示例:
假设有如下两个 Bean:
public class A {
private B b;
// setter ...
}
public class B {}
当 Spring 创建 a 这个 Bean 时,会发现它有一个未赋值的属性 b ,并且容器中存在名为 b 的 Bean。于是调用 registerDependentBean("b", "a") ,表示:
Bean
a依赖于 Beanb
作用:
-
维护依赖关系图谱
- Spring 使用这个信息来维护一个依赖关系图,用于后续的销毁顺序、循环依赖检测等。
-
控制销毁顺序
- 当应用关闭时,Spring 会按照依赖顺序反向销毁 Bean。例如,如果
a依赖b,那么先销毁a,再销毁b。
- 当应用关闭时,Spring 会按照依赖顺序反向销毁 Bean。例如,如果
-
支持
depends-on特性- 即使没有显式使用
<bean depends-on="xxx">,隐式的依赖也会被记录下来,确保启动和销毁顺序正确。
- 即使没有显式使用
-
循环依赖检测
- 在创建 Bean 时,Spring 会检查是否存在循环依赖(如
a → b → a),并给出相应的错误提示或尝试解决。
- 在创建 Bean 时,Spring 会检查是否存在循环依赖(如
-
获取依赖链
- 可以通过
BeanFactory.getDependenciesForBean("a")获取某个 Bean 所依赖的其他 Bean。
- 可以通过
实现细节:
DefaultSingletonBeanRegistry 内部维护了两个 Map:
// 某个 Bean 所依赖的其他 Bean 列表
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>();
// 某个 Bean 被哪些其他 Bean 所依赖
private final Map<String, Set<String>> dependentBeansMap = new ConcurrentHashMap<>();
调用 registerDependentBean("b", "a") 后:
dependenciesForBeanMap.get("a")中会包含"b"—— 表示 a 依赖 b。dependentBeansMap.get("b")中会包含"a"—— 表示 b 被 a 依赖。
关键点
| 方法/逻辑 | 作用 |
|---|---|
unsatisfiedNonSimpleProperties(...) | 获取未赋值的、非简单类型的属性名 |
containsBean(propertyName) | 检查是否有一个名称匹配的 Bean 存在 |
getBean(propertyName) | 获取匹配的 Bean 实例 |
pvs.add(...) | 将属性与 Bean 绑定,实现自动装配 |
registerDependentBean(...) | 注册 Bean 间的依赖关系 |
3. autowireByType(...) 方法
/**
* 定义“按类型自动装配”(autowire by type)的行为。
* <p>
* 类似于 PicoContainer 的默认行为,要求容器中必须有且只有一个指定类型的 Bean。
* 这种方式在小型应用中配置简单,但在大型项目中不如 Spring 默认的自动装配机制灵活。
*
* @param beanName 被按类型自动装配的 Bean 的名称
* @param mbd 用于更新自动装配信息的合并后的 BeanDefinition
* @param bw 通过 BeanWrapper 可以获取当前 Bean 的属性信息
* @param pvs 用于注册已自动装配的属性值集合
*/
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取自定义的类型转换器,如果没有则使用 BeanWrapper 自带的
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
// 获取所有未被赋值的、非简单类型的属性名(即可能是需要依赖注入的对象)
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 用于存储匹配到的依赖 Bean 名称
Set<String> autowiredBeanNames = new LinkedHashSet<>(propertyNames.length * 2);
// 遍历这些属性,进行按类型自动装配
for (String propertyName : propertyNames) {
try {
// 获取该属性的描述符(PropertyDescriptor),包括 getter/setter 等信息
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 不对 Object 类型进行自动装配,因为没有实际意义
if (Object.class != pd.getPropertyType()) {
// 获取该属性对应的写方法参数(setter 方法参数)
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// 如果当前 Bean 是 PriorityOrdered 类型,则不允许提前初始化依赖对象
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
// 创建依赖描述符,用于后续解析依赖
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析依赖项,从容器中找到匹配的 Bean 实例
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
// 如果找到了合适的依赖对象,就添加到属性集合中
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
// 注册依赖关系:当前 Bean(beanName)依赖于 autowiredBeanName
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
// 清空本次查找的依赖 Bean 名称集合,准备处理下一个属性
autowiredBeanNames.clear();
}
} catch (BeansException ex) {
// 抛出依赖不满足异常
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
方法流程
实现了 按类型自动装配 的逻辑:
-
筛选属性:
- 找出当前 Bean 中尚未设置值的、非简单类型的属性(如
int,String等不会被自动装配)。
- 找出当前 Bean 中尚未设置值的、非简单类型的属性(如
-
解析依赖:
- 对每个这样的属性,尝试根据其类型从 Spring 容器中找出一个匹配的 Bean。
-
设置属性值:
- 将找到的 Bean 添加到要设置的属性值集合
pvs中。
- 将找到的 Bean 添加到要设置的属性值集合
-
记录依赖关系:
- 使用
registerDependentBean(dependentBeanName, dependingOnBeanName)记录 Bean 之间的依赖关系,以便后续管理生命周期和销毁顺序。
- 使用
-
日志输出:
- 在调试模式下输出自动装配过程的日志信息。
示例
假设有如下两个类:
public class A {
private B b;
}
public class B {}
当 Spring 创建 a 这个 Bean 时,发现它有一个属性 b 类型为 B ,并且容器中存在一个 B 类型的 Bean b ,就会调用这个方法,并最终将 b 注入到 a 中。同时会调用:
registerDependentBean("b", "a");
表示:Bean a 依赖于 Bean b。
六、AutowiredAnnotationBeanPostProcessor
1. 注册
详见这篇
2. 实现 InstantiationAwareBeanPostProcessor
所以能被 AbstractAutowireCapableBeanFactory.populateBean(...) 方法调用
3. 作用
这个处理器负责处理 @Autowired、@Value、@Inject 注解。
4. 构造函数
/**
* 创建一个新的 AutowiredAnnotationBeanPostProcessor 实例,用于处理 Spring 标准的
* {@link Autowired @Autowired} 和 {@link Value @Value} 注解。
*
* <p>如果类路径中存在 Jakarta EE 的依赖,还会自动支持标准的
* {@link jakarta.inject.Inject @Inject} 注解作为替代方案。
*
* <p>该处理器会在 Spring 容器初始化 Bean 的过程中自动检测并注入带有这些注解的字段、方法和构造函数。
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
// 添加 Spring 自带的两个自动装配注解类型
this.autowiredAnnotationTypes.add(Autowired.class); // 支持 @Autowired
this.autowiredAnnotationTypes.add(Value.class); // 支持 @Value
// 尝试加载 Jakarta 的 @Inject 注解(如果可用)
ClassLoader classLoader = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
try {
// 动态加载 jakarta.inject.Inject 类
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("jakarta.inject.Inject", classLoader));
logger.trace("'jakarta.inject.Inject' 注解已找到,将被用于自动装配");
}
catch (ClassNotFoundException ex) {
// 如果没有找到 jakarta.inject.Inject,则忽略此注解,不启用相关功能
// 日志无需输出,因为这是可选依赖项
}
}
5. postProcessProperties(...) 方法
/**
* 在 Bean 的属性填充阶段,处理带有自动装配注解(如 @Autowired、@Value 等)的字段和方法,
* 并将匹配的依赖项注入到目标 Bean 中。
*
* <p>该方法是 Spring 的 {@link SmartInstantiationAwareBeanPostProcessor} 接口定义的一部分,
* 会在 Bean 实例化之后、属性赋值之前被调用。
*
* @param pvs 要应用到 Bean 的属性值集合(可能包含 XML 配置等来源的值)
* @param bean 正在处理的目标 Bean 实例
* @param beanName 当前 Bean 的名称
* @return 返回处理后的属性值集合(通常原样返回,因为主要作用是注入依赖)
* @throws BeanCreationException 如果依赖注入失败
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 查找当前 Bean 类中所有需要自动注入的字段和方法的元数据
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 执行实际的依赖注入操作
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
// 捕获并包装其他异常为 BeanCreationException,便于调试和日志记录
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
🧠 方法流程
| 步骤 | 描述 |
|---|---|
| ✅ 查找注入元数据 | 调用 findAutowiringMetadata() 方法,扫描当前类及其父类中所有带有自动装配注解的字段和方法,并缓存这些信息 |
| ✅ 执行注入 | 调用 metadata.inject(...),依次对每个标记了 @Autowired、@Value 等注解的字段或方法进行依赖解析和注入 |
| ✅ 异常处理 | 捕获注入过程中可能出现的异常,并封装为 BeanCreationException 抛出,统一异常处理逻辑 |
🔍 关键点
InjectionMetadata:保存了某个类中所有可注入的元素(字段、方法),并提供inject()方法用于执行实际的注入操作。findAutowiringMetadata(...):会优先从缓存中获取已构建好的注入信息;如果没有,则通过反射扫描类结构生成新的元数据。metadata.inject(...):具体完成字段/方法的依赖查找和设置值的操作。
💡 示例
假设有如下类:
@Component
public class MyService {
@Autowired
private MyRepository repository;
public void doSomething() {
repository.save();
}
}
当 Spring 创建 MyService 实例时:
- 会调用
postProcessProperties(); - 找到
repository字段上的@Autowired; - 从容器中查找
MyRepository类型的 Bean; - 将其注入到
repository字段中;
6. findAutowiringMetadata(...) 方法
/**
* 查找指定类中所有需要自动装配(如 @Autowired、@Value 等)的字段和方法,并构建对应的注入元数据。
*
* <p>该方法会优先从缓存中获取已构建好的元数据,如果发现类结构发生变化或缓存为空,
* 则重新构建元数据以确保注入信息是最新的。
*
* @param beanName 当前 Bean 的名称,用于生成缓存键
* @param clazz 要分析的类类型
* @param pvs 属性值集合,用于清理旧的注入配置(可选)
* @return 注入元数据对象,包含所有可注入的字段和方法
*/
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 如果没有提供 beanName,则使用类名作为缓存键
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 先尝试从缓存中获取元数据,避免重复解析
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 检查是否需要刷新元数据(例如类结构变化或首次加载)
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
// 再次检查缓存,防止并发重复构建
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 如果已有旧元数据,先清理其关联的配置
if (metadata != null) {
metadata.clear(pvs);
}
// 构建新的注入元数据
metadata = buildAutowiringMetadata(clazz);
// 将新构建的元数据缓存起来
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
// 返回找到或新建的注入元数据
return metadata;
}
🧠 方法流程
| 步骤 | 描述 |
|---|---|
| ✅ 确定缓存键 | 优先使用 beanName,否则使用类名作为缓存键 |
| ✅ 尝试从缓存获取 | 避免重复扫描和构建元数据,提高性能 |
| ✅ 判断是否需要刷新 | 如果当前类与缓存中的元数据不一致,则需重建 |
| ✅ 加锁同步处理 | 防止多线程下重复构建元数据 |
| ✅ 清理旧元数据 | 如果之前有元数据,调用 clear() 清理旧配置 |
| ✅ 构建新元数据 | 调用 buildAutowiringMetadata(clazz) 实际进行扫描和构建 |
| ✅ 缓存并返回 | 新的元数据会被缓存以便下次使用 |
🔍 关键点
InjectionMetadata:封装了某个类中所有需要注入的字段和方法的信息,支持缓存和重用。needsRefresh(...):判断当前缓存中的元数据是否适用于传入的类。如果不适用(比如类结构变化),则返回true。buildAutowiringMetadata(clazz):实际执行反射扫描的方法,查找带有自动装配注解的成员。
💡 示例
假设有一个如下类:
@Component
public class MyService {
@Autowired
private MyRepository repository;
@Value("${app.url}")
private String appUrl;
public void init() {
System.out.println(appUrl);
}
}
当 Spring 创建这个 Bean 时:
- 会调用
findAutowiringMetadata("myService", MyService.class, null); - 通过反射扫描
MyService.class,找到repository和appUrl字段; - 构建出一个
InjectionMetadata对象,记录这两个字段及其依赖信息; - 后续调用
inject(...)时,Spring 会根据这些元数据注入相应的依赖。
7. 小结
✅ 支持的注解
| 注解 | 是否支持 | 说明 |
|---|---|---|
@Autowired | ✅ 是 | 默认支持,由 Spring 提供,是最常用的自动装配注解。 |
@Value | ✅ 是 | 默认支持,用于注入外部配置值(如 @Value("${my.property}"))。 |
@Inject | ✅ 是(可选) | 如果项目中存在 jakarta.inject.Inject(或旧版 javax.inject.Inject),则会动态加载并支持该注解。 |
@Resource | ❌ 否 | 不支持,这是 JSR-250 标准注解,由 CommonAnnotationBeanPostProcessor 处理,不在AutowiredAnnotationBeanPostProcessor处理范围内。 |
七、总结
| 特性 | 内容 |
|---|---|
| 核心机制 | 基于反射 + 注解 + 容器管理 |
| 主要类 | BeanFactory, ApplicationContext, BeanPostProcessor, AutowiredAnnotationBeanPostProcessor |
| 依赖注入方式 | 构造器注入、Setter 注入、字段注入 |
| 注解支持 | @Autowired, @Resource, @Inject, @Value |
| 循环依赖 | 单例 Bean 支持解决(非构造器注入) |
| 源码入口 | AbstractAutowireCapableBeanFactory, AutowiredAnnotationBeanPostProcessor |
| 注解 | 所属规范 | 处理类 |
|---|---|---|
@Autowired | Spring 内置 | AutowiredAnnotationBeanPostProcessor |
@Value | Spring 内置 | AutowiredAnnotationBeanPostProcessor |
@Inject | Jakarta EE (JSR-330) | AutowiredAnnotationBeanPostProcessor |
@Resource | Java EE (JSR-250) | CommonAnnotationBeanPostProcessor |
1667

被折叠的 条评论
为什么被折叠?



