Spring 的 依赖注入

Spring 的 依赖注入 是 Spring 框架的核心特性之一。它通过容器管理对象之间的依赖关系,实现解耦、可测试性和灵活性。


一、什么是依赖注入?

依赖注入是一种设计模式,其核心思想是:由外部容器来管理对象的创建和依赖关系,而不是在类内部硬编码依赖对象。

例如:

public class UserService {
    private UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

这里 UserService 不自己创建 UserRepository 实例,而是通过构造函数由外部传入,这就是依赖注入。


二、Spring 中的依赖注入方式

Spring 支持以下几种依赖注入方式:

  1. 构造器注入
  2. Setter 注入
  3. 字段注入(@Autowired)
  4. 方法注入(如 @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 容器完成依赖注入的关键类包括:

类名功能
BeanFactorySpring 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

  • 调用 @PostConstructInitializingBean 接口方法。
  • 调用自定义初始化方法(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);
    }
}

方法流程

  1. 空值校验

    • 如果 BeanWrappernull 并且有属性值需要设置,则抛出异常。
    • 如果是 Java Record 类型,并且有属性值要设置,也抛出异常。
  2. postProcessAfterInstantiation 后处理器

    • 允许 InstantiationAwareBeanPostProcessor 修改 Bean 状态,例如 AutowiredAnnotationBeanPostProcessor
    • 如果返回 false,直接跳过后续属性填充。
  3. 自动装配逻辑

    • 若启用 autowire="byName",调用 autowireByName(),根据属性名从容器中查找匹配的 Bean 注入。
    • 若启用 autowire="byType",调用 autowireByType(),根据属性类型从容器中查找匹配的 Bean 注入。
  4. postProcessProperties 属性修改

    • 允许 InstantiationAwareBeanPostProcessor 修改最终的属性值列表,例如 AutowiredAnnotationBeanPostProcessor
    • 如果返回 null,表示跳过后续操作。
  5. 依赖检查

    • 检查是否有未满足的依赖项,比如某些属性没有被赋值。
    • 可以选择检查简单属性、对象属性或全部属性。
  6. 属性值应用

    • 调用 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(...) 方法:

  • 发现其属性 userRepositoryUserRepository 类型;
  • 自动查找并注入容器中唯一的 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");
			}
		}
	}
}

方法流程

  1. 获取未满足的非简单属性

    • 调用 unsatisfiedNonSimpleProperties(mbd, bw) 获取当前 Bean 中未被赋值的、且不是简单类型的属性名数组。
  2. 遍历每个属性

    • 对每一个未满足的属性进行处理。
  3. 检查容器中是否存在同名 Bean

    • 使用 containsBean(propertyName) 判断是否存在一个名称与属性名相同的 Bean。
  4. 自动装配

    • 如果存在,则通过 getBean(propertyName) 获取该 Bean;
    • 将其添加到 pvs 中,表示该属性应被自动注入。
  5. 注册依赖关系

    • 调用 registerDependentBean(propertyName, beanName),注册两个 Bean 之间的依赖关系。
  6. 日志记录

    • 如果启用 trace 日志级别,记录装配过程的信息或失败原因。

registerDependentBean(...)

示例:

假设有如下两个 Bean:

public class A {
    private B b;
    // setter ...
}

public class B {}

当 Spring 创建 a 这个 Bean 时,会发现它有一个未赋值的属性 b ,并且容器中存在名为 b 的 Bean。于是调用 registerDependentBean("b", "a") ,表示:

Bean a 依赖于 Bean b

作用:
  1. 维护依赖关系图谱

    • Spring 使用这个信息来维护一个依赖关系图,用于后续的销毁顺序、循环依赖检测等。
  2. 控制销毁顺序

    • 当应用关闭时,Spring 会按照依赖顺序反向销毁 Bean。例如,如果 a 依赖 b ,那么先销毁 a ,再销毁 b
  3. 支持 depends-on 特性

    • 即使没有显式使用 <bean depends-on="xxx">,隐式的依赖也会被记录下来,确保启动和销毁顺序正确。
  4. 循环依赖检测

    • 在创建 Bean 时,Spring 会检查是否存在循环依赖(如 a → b → a),并给出相应的错误提示或尝试解决。
  5. 获取依赖链

    • 可以通过 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);
        }
    }
}

方法流程

实现了 按类型自动装配 的逻辑:

  1. 筛选属性

    • 找出当前 Bean 中尚未设置值的、非简单类型的属性(如 int, String 等不会被自动装配)。
  2. 解析依赖

    • 对每个这样的属性,尝试根据其类型从 Spring 容器中找出一个匹配的 Bean。
  3. 设置属性值

    • 将找到的 Bean 添加到要设置的属性值集合 pvs 中。
  4. 记录依赖关系

    • 使用 registerDependentBean(dependentBeanName, dependingOnBeanName) 记录 Bean 之间的依赖关系,以便后续管理生命周期和销毁顺序。
  5. 日志输出

    • 在调试模式下输出自动装配过程的日志信息。

示例

假设有如下两个类:

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 实例时:

  1. 会调用 postProcessProperties()
  2. 找到 repository 字段上的 @Autowired
  3. 从容器中查找 MyRepository 类型的 Bean;
  4. 将其注入到 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 时:

  1. 会调用 findAutowiringMetadata("myService", MyService.class, null)
  2. 通过反射扫描 MyService.class,找到 repositoryappUrl 字段;
  3. 构建出一个 InjectionMetadata 对象,记录这两个字段及其依赖信息;
  4. 后续调用 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
注解所属规范处理类
@AutowiredSpring 内置AutowiredAnnotationBeanPostProcessor
@ValueSpring 内置AutowiredAnnotationBeanPostProcessor
@InjectJakarta EE (JSR-330)AutowiredAnnotationBeanPostProcessor
@ResourceJava EE (JSR-250)CommonAnnotationBeanPostProcessor

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值