美文网首页Spring IOC源码解读
spring源码日记15: 属性填充

spring源码日记15: 属性填充

作者: BugPool | 来源:发表于2020-02-23 11:37 被阅读0次

所有文章已迁移至csdn,csdn个人主页https://blog.csdn.net/chaitoudaren

spring属性注入分4种:

  1. 不开启自动注入,即xml自己配置property
  2. 通过名称自动注入
  3. 通过类型自动注入
  4. @Autowire自动注入

本篇我们将介绍前三种,@Autowire应该是百分之99的开发者选择的的注入方式,它通过属性填充中的后置处理器完成,因此本篇有涉及后置处理器的不用太纠结,将单独一片详解:spring源码日期16: @Autowired实现原理

下方代码,本篇只关心第4点属性填充

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
        ...
        try {
            //
            /**
             * 4. 填充属性
             * 如果@Autowired注解属性,则在上方完成解析后,在这里完成注入
             *
             * @Autowired
             * private Inner inner;
             */
            populateBean(beanName, mbd, instanceWrapper);
            // 5. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        ...
}

属性填充

    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 {
                // Skip property population phase for null instance.
                // 没有属性就直接返回
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        // 1. 实例化后的后置操作
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        // 实例化后置处理器可以发出终止填充的命令,这点比较特别
                        return;
                    }
                }
            }
        }
        // 2. 获取属性值
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        // 3. 根据注入方式的不同可分为 通过 ①名称注入、②类型注入、③不自动注入
        /**
         * ①按名称注入,则pvs在步骤2时会获取到配置文件中配置注入的属性,同时在autowireByName又会进一步通过名称添加补充
         * ②按名称注入,则pvs在步骤2时会获取到配置文件中配置注入的属性,同时在autowireByType又会进一步通过类型添加补充
         * ③不开启自动注入,则在步骤2 pvs就可以获取到配置文件中注入的属性
         */
        int resolvedAutowireMode = mbd.getResolvedAutowireMode();
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                // ①通过名称自动注入
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                // ②通过类型自动注入
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }

        // 判断所有实例化后置处理器是否都已经初始化完成
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        // 依赖检测
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            /**
             * 4. 属性填充的后置处理器
             * @Autowired
             * private Inner inner;
             * 在这里使用AutowiredAnnotationBeanPostProcessor进行注入
             */
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // @Autowired正是在这里调用后置处理器对属性进行注入
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        // 对所有需要检测的属性进行后置处理
                        pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }
                    pvs = pvsToUse;
                }
            }
        }
        if (needsDepCheck) {
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }

        if (pvs != null) {
            // 5. 将属性应用到bean中
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }
  1. 实例化后置处理
  2. 获取属性值
    这边获取到的pvs是从配置文件中获取的,代码如下,xml配置文件中property标签仅包含b1,所以pvs仅仅会获取到b1,如果没有下一步的代码将不会注入b2(这点很容易被忽视,一定引起重视)
public Class A {
    private B1 b1;
    private B2 b2;
    // getter&&setter
}
public Class B1 {}
public Class B2 {}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
       default-autowire="byName"
>
    <bean id="a" class="autowire.A">
        <property name="b1" ref="b1"/>
    </bean>

    <bean id="b1" class="B1"/>
    <bean id="b2" class="B2"/>
</beans>
  1. 自动注入(其实这里只是获取待注入属性,并未开始实际的注入操作)
    还是上方代码,注意一定要加上default-autowire="byName"这句,这句指开启按名称注入,否则spring默认不开启自动注入。开启后,spring将通过Class A类中的属性,按名称b2通过getBean("b2")的方式进行查找,并将它添加到pvs中,至此属性b1, b2才都被成功添加到pvs中,等待注入
    protected void autowireByName(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
        // 获取pvs以外的其他属性,该属性必须有setter方法
        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            if (containsBean(propertyName)) {
                // 直接通过属性名获取bean,并假如到pvs中
                Object bean = getBean(propertyName);
                pvs.add(propertyName, 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 {
                if (logger.isTraceEnabled()) {
                    logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                            "' by name: no matching bean found");
                }
            }
        }
    }
  1. 属性填充的后置处理器,@Autowire正是在这里注入的,我们将单独一章详解:spring源码日期16: @Autowired实现原理
  2. 将属性注入到bean中
    代码很大一部分工作用在了属性转换上,例如property传入String类型而实际属性则为int类型,当然这是最简单的一种。而我们最关心的注入操作则发生在第6步,具体代码很长就不详细分析了,但是最核心的操作则是通过反射获取到对应属性field,然后调用field.set(bean, property);实现对bean属性的赋值
    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        // 1. pvs为空就没得注入了
        if (pvs.isEmpty()) {
            return;
        }

        // 2. 权限管理器
        if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }

        //MutablePropertyValues是PropertyValues接口的默认实现类
        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        // 3. 获取bean的属性集合
        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            // pvs都需要被转换成对应的类型才可以应用到beanwapper中
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                // 如果pvs已经转换过,则直接设置属性值无需再次转换
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            // 否则获取原始PropertyValue集合
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        // 4. 获取类型转换器
        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.
        // 5. 通过深度拷贝,解析值引用
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;
        // 循环转换PropertyValues
        for (PropertyValue pv : original) {
            // 已经转换过,则直接加入deepCopy
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            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);
                }

                // 解析原始属性值
                // 当注入集合属性时,如果指定了value-type,如value-type="java.lang.String",那么resolveValueIfNecessary会执行类型的转换操作
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;

                // isWritableProperty判断属性是否可写,isNestedOrIndexedProperty判断是否索引属性或者嵌套属性
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                // 是否转换
                if (convertible) {
                    // 类型转换
                    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.
                // 缓存已经转换过的值,避免再次转换。这取决于convertForProperty是否真正对属性进行了转换
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            // 6. 设置属性值,实质就是通过反射调用对属性进行赋值
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

相关文章

网友评论

    本文标题:spring源码日记15: 属性填充

    本文链接:https://www.haomeiwen.com/subject/kfzrqhtx.html