SpringIOC之Bean属性填充的逻辑

文章详细介绍了Spring框架在创建Bean时的内部流程,特别是依赖注入的过程。从调用AbstractBeanFactory的getBean方法开始,通过AbstractAutowireCapableBeanFactory的createBean方法创建Bean。在Bean实例化后,通过不同的方式如名称、类型匹配来寻找并注入属性值。此外,文章提到了Spring内部的InstantiationAwareBeanPostProcessor处理器,如AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor,它们分别处理@Autowired、@Value和@Resource注解的属性值。最后,通过反射机制将所有属性值设置到Bean中。

总体流程总结:

当我们显示或者隐式地调用AbstractBeanFactory 的 getBean(...) 方法时,会触发 Bean 的加载。
对于不同作用域的 Bean,底层都会调用 AbstractAutowireCapableBeanFactory 的 createBean(...)方法进行创建。
创建 Bean 的过程中,获取到的一个实例对象后,需要获取相关属性值,然后注入到 Bean 中,其中获取属性值有三种模式:
AUTOWIRE_NO,默认,不获取相关属性值
AUTOWIRE_BY_NAME,通过名称获取没有定义属性值的"对象"的属性值,通过 getBean(String beanName) 查找
AUTOWIRE_BY_TYPE,通过类型获取没有定义属性值的"对象"的属性值,依赖注入的方式
默认情况下,获取到已定义的属性值后不会通过上面的方式去找属性值,在后续有一个属性值的后置处理,
会调用所有的 InstantiationAwareBeanPostProcessor 处理器的 postProcessProperties 方法进行处理,例如 Spring 内部有两个 InstantiationAwareBeanPostProcessor 处理器:
AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解标注的属性,获取对应属性值
CommonAnnotationBeanPostProcessor,会解析 @Resource 注解标注的属性,获取对应的属性值
在获取到所有的属性值后然后通过反射机制设置到 Bean 中

    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        // <1> 没有相关属性值,则直接 `return` 返回
        if (pvs.isEmpty()) {
            return;
        }

        if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }
        // ------------------------开始属性值的转换与填充------------------------
        MutablePropertyValues mpvs = null;
        // 定义一个 `original` 集合,承载属性值(未进行转换)
        List<PropertyValue> original;
        // <2> 如果 `pvs` 是 MutablePropertyValues 类型,则可能已经处理过了
        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    // <2.1> 属性值已经转换了,则将这些属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            // <2.2> 没有转换过,则获取所有的属性值集合
            original = mpvs.getPropertyValueList();
        }
        else {
            // <2.2> 获取所有的属性值集合
            original = Arrays.asList(pvs.getPropertyValues());
        }
        // 获取 TypeConverter 类型转换器,用于取代默认的 PropertyEditor 类型转换器
        // 例如 Spring 3.0 之后的 ConversionService
        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        // 获取对应的解析器
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        // <3> 定义一个 `deepCopy` 集合,保存转换后的属性值
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;
        // <4> 遍历所有的属性值,进行转换(如果有必要)
        for (PropertyValue pv : original) {
            // <4.1> 已经转换过,则直接添加到 `deepCopy` 中
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            // <4.2> 否则,开始进行转换
            else {
                String propertyName = pv.getName();
                // 转换之前的属性值
                Object originalValue = pv.getValue();
                if (originalValue == AutowiredPropertyMarker.INSTANCE) {
                    Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
                    if (writeMethod == null) {
                        throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
                    }
                    originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
                }
                // <4.2.1> 表达式的处理(如果有必要的话),例如你在 XML 配置的属性值为 `${systenm.user}`,则会解析出对应的值
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                // 转换之后的属性值
                Object convertedValue = resolvedValue;
                // 该属性是否可以转换
                boolean convertible = bw.isWritableProperty(propertyName) && // 属性可写
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);// 不包含 `.` 和 `[`
                if (convertible) {
                    // <4.2.2> 使用类型转换器转换属性值(如果有必要的话)
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {// 属性值没有转换过
                    if (convertible) {
                        // <4.2.3> 设置转换后的值,避免上面的各种判断
                        pv.setConvertedValue(convertedValue);
                    }
                    // <4.2.4> 添加到 `deepCopy` 中
                    deepCopy.add(pv);
                }
                // 属否则属性值进行了转换
                else if (convertible // 可转换的
                        && originalValue instanceof TypedStringValue && // 属性原始值是字符串类型
                        !((TypedStringValue) originalValue).isDynamic() &&  // 属性的原始类型值不是动态生成的字符串
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { // 属性的原始值不是集合或者数组类型
                    // <4.2.3> 设置转换后的值,避免上面的各种判断
                    pv.setConvertedValue(convertedValue);
                    // <4.2.4> 添加到 `deepCopy` 中
                    deepCopy.add(pv);
                }
                // 否则
                else {
                    // 这个属性每次都要处理,不能缓存
                    resolveNecessary = true;
                    // <4.2.4> 添加到 `deepCopy` 中
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        // <5> 如果属性值不为空,且不需要每次都处理,则设置为已转换
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            // <6> 将属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

过程大致如下:

  1. 没有相关属性值,则直接 return 返回


开始属性值的转换与填充,先定义一个 original 集合,承载属性值(未进行转换)

  1. 如果 pvs 是 MutablePropertyValues 类型,则可能已经处理过了,否则,获取所有的属性值集合,放入 original 集合中

  1. 属性值已经转换了,则将这些属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!

调用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法

  1. 没有转换过,则获取所有的属性值集合,放入 original 集合中

  1. 定义一个 deepCopy 集合,保存转换后的属性值

  1. 遍历所有的属性值,进行转换(如果有必要)

  1. 已经转换过,则直接添加到 deepCopy

  1. 否则,开始进行转换

  1. 表达式的处理(如果有必要的话),例如你在 XML 配置的属性值为 ${systenm.user},则会解析出对应的值

  1. 使用类型转换器转换属性值(如果有必要的话)

  1. 设置转换后的值,避免上面的各种判断

  1. 添加到 deepCopy

  1. 如果属性值不为空,且不需要每次都处理,则设置为已转换

  1. 将属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现

调用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法


整个属性注入过程非常复杂,上面仅列出了关键步骤,可以看到最终会调用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法将属性值设置到 Bean 中

在 Bean 的实例化阶段获取到的就是一个 BeanWrapperImpl 对象,所以这里调用的就是当前 Bean 的 setPropertyValues(PropertyValues) 方法,该方法的底层借助于 Java Beans 的 java.beans.PropertyDescriptor 属性描述器,获取到对应的写方法,然后通过反射机制设置当前 Bean 的属性值

<think>我们正在讨论Spring IOC属性注入的底层实现原理。根据用户的问题和之前的回答,我们需要深入探讨Spring如何实现属性注入,包括注解处理、反射机制、依赖查找和注入过程等。 参考引用: [^1]提到Spring IOC的基本概念和依赖注入方式。 [^2]详细介绍了IOC容器的设计原理和体系结构。 [^3]包含了IOC的底层原理、初始化流程和操作方式(XML和注解)。 [^4]特别指出Spring通过反射机制读取注解(如@Autowired、@Resource)并实现注入,底层使用Field.set()或Method.invoke()。 因此,我们将围绕以下核心点展开: 1. Spring IOC容器如何管理Bean的依赖关系? 2. 注解(如@Autowired)是如何被处理的? 3. 反射在属性注入中的作用。 4. 循环依赖的解决机制(三级缓存)。 回答结构: 1. 总体流程概述 2. 关键组件分析(BeanDefinition、BeanPostProcessor等) 3. 注解解析与反射注入的详细步骤 4. 循环依赖处理 5. 相关问题生成 注意:使用中文,并按照要求处理数学公式(虽然本问题可能不涉及数学公式,但若有表达式则按格式处理)。</think>### Spring IOC 属性注入底层实现原理详解 Spring IOC 属性注入的核心是通过**反射机制**和**容器管理**实现依赖关系的自动装配,其底层流程可分为以下关键步骤: --- #### 一、容器初始化阶段 1. **BeanDefinition 加载** Spring 解析配置(XML/注解/JavaConfig)生成 `BeanDefinition` 对象,存储 Bean 的元数据: ```java public interface BeanDefinition { String getBeanClassName(); // Bean 类名 PropertyValues getPropertyValues(); // 需注入属性 ConstructorArgumentValues getConstructorArgumentValues(); // 构造参数 } ``` - XML 配置通过 `BeanDefinitionParser` 解析 `<property>` 标签[^3] - 注解配置通过 `ClassPathScanningCandidateComponentProvider` 扫描 `@Component` 等注解[^2] 2. **注册 BeanDefinition** 所有 `BeanDefinition` 存入 `BeanDefinitionRegistry`(核心实现类:`DefaultListableBeanFactory`): ```java beanFactory.registerBeanDefinition("userService", userDefinition); ``` --- #### 二、依赖注入执行阶段 当容器实例化 Bean 时,通过以下流程完成属性注入: ##### 1. **实例化对象** - 调用 `InstantiationStrategy`(默认 `CglibSubclassingInstantiationStrategy`) - 通过反射 `Constructor.newInstance()` 创建原始对象 ##### 2. **属性填充(关键步骤)** - **步骤 1:依赖解析** 检查 `BeanDefinition` 中的 `PropertyValues`,确定需注入属性: ```java for (PropertyValue pv : beanDefinition.getPropertyValues()) { String propertyName = pv.getName(); // 如 "userDao" Object value = pv.getValue(); // 引用类型为 RuntimeBeanReference } ``` - **步骤 2:依赖查找** 对引用类型属性(如 `userDao`),通过 `BeanFactory.getBean()` 从容器获取依赖对象: ```java Object resolvedValue = resolveReference(propertyName, (RuntimeBeanReference) value); ``` - **步骤 3:反射注入** 使用反射 API 将值注入目标属性: ```java Field field = targetClass.getDeclaredField("userDao"); field.setAccessible(true); field.set(beanInstance, resolvedValue); // 关键注入操作 ``` 或通过 Setter 方法注入: ```java Method setter = targetClass.getMethod("setUserDao", UserDao.class); setter.invoke(beanInstance, resolvedValue); ``` ##### 3. **注解处理(@Autowired/@Resource)** - **`AutowiredAnnotationBeanPostProcessor`** 扫描 `@Autowired` 注解字段/方法 - 通过 `InjectionMetadata` 收集所有需注入的元素: ```java List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); elements.add(new AutowiredFieldElement(field, required)); ``` - 最终调用 `Field.set()` 或 `Method.invoke()` 完成注入[^4] --- #### 三、循环依赖解决方案(三级缓存) 当发生属性注入的循环依赖(如 A → B → A),Spring 通过三级缓存解决: ```java // DefaultSingletonBeanRegistry 中的三级缓存 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 一级缓存(完整Bean) private final Map<String, Object> earlySingletonObjects = new HashMap<>(); // 二级缓存(早期引用) private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(); // 三级缓存(对象工厂) ``` **解决流程**: 1. 创建 A 实例后,将原始对象包装为 `ObjectFactory` 放入三级缓存 2. 为 A 注入属性时发现依赖 B,触发 B 的创建 3. 为 B 注入属性时从三级缓存获取 A 的早期引用(未完全初始化的 A) 4. B 完成初始化后,A 继续注入完整的 B 实例[^2] > ⚠️ **限制**:仅支持单例模式下的Setter/字段注入,构造器注入的循环依赖会抛出 `BeanCurrentlyInCreationException` --- #### 四、扩展机制支撑 Spring 通过扩展点增强注入能力: 1. **`BeanPostProcessor`** 在注入前后插入自定义逻辑(如 `@Autowired` 由 `AutowiredAnnotationBeanPostProcessor` 实现) 2. **`BeanFactoryPostProcessor`** 修改 `BeanDefinition`(如 `PropertySourcesPlaceholderConfigurer` 解析 `${}` 占位符) 3. **`InstantiationAwareBeanPostProcessor`** 控制实例化过程(如 AOP 代理对象的生成) --- ### 原理总结 | 关键机制 | 实现组件 | 作用 | |------------------|-----------------------------------|--------------------------------------| | 元数据管理 | `BeanDefinition` | 存储 Bean 的依赖关系 | | 依赖解析 | `DependencyDescriptor` | 描述注入点(字段/方法参数) | | 反射注入 | `Field.set()`/`Method.invoke()` | 实际注入操作 | | 注解处理 | `AutowiredAnnotationBeanPostProcessor` | 解析 `@Autowired`/`@Value` | | 循环依赖解决 | 三级缓存机制 | 打破单例 Bean 循环依赖 | > 整个流程体现了 **控制反转** 的核心思想:开发者定义依赖关系,容器负责装配实现[^1]。 --- ### 相关问题 1. Spring 如何解决构造器注入的循环依赖问题? 2. `@Autowired` 和 `@Resource` 注解在注入流程中有何本质区别? 3. 如何通过自定义 `BeanPostProcessor` 实现加密属性的自动解密? 4. 为什么字段注入(`@Autowired`)比 Setter 注入更容易导致循环依赖问题? [^1]: Spring IOC详解:从原理到实战 [^2]: Spring IOC体系结构设计原理详解 [^3]: Spring IOC详解 - IOC操作Bean管理(XML方式) [^4]: spring ioc实现原理 - 反射机制实现依赖注入
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder_Boy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值