Spring IOC 之 属性注册编辑器PropertyEditorRegistry源码

自定义属性编辑器有两种方式
第一种方式:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
   <property name="customEditors">
      <map>
         <!-- 可以这样写:map中的value以String类型"org.spring.support.DatePropertyEditor"存储 -->
         <!--<entry key="java.util.Date" value="org.spring.support.DatePropertyEditor"/>-->

         <!-- 也可以这样写:map中的value以Class类型org.spring.support.DatePropertyEditor存储 -->
         <!--<entry key="java.util.Date" value="org.spring.support.DatePropertyEditor" value-type="java.lang.Class"></entry>-->

         <!-- 也可以这样写:map中的value以PropertyEditor类型org.spring.support.DatePropertyEditor存储 -->
         <entry key="java.util.Date">
            <bean class="org.spring.support.DatePropertyEditor"></bean>
         </entry>
      </map>
   </property>

java 代码:

public class DatePropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws java.lang.IllegalArgumentException {
        try {
            setValue(new SimpleDateFormat("yyyy-MM-dd").parse(text));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

第二种方式:

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
   <list>
      <bean class="org.spring.support.LocalDatePropertyEditorRegistrar"></bean>
   </list>
</property>

java 代码:

public class LocalDatePropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) {
        setValue(LocalDate.parse(text));
    }
}
public class LocalDatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(LocalDate.class, new LocalDatePropertyEditor());
    }
}

一旦spring bean类中有Date或者LocalDate类型属性字段时,则可以将xml中配置的字符串值转化为Date、LocalDate,具体应用如下:

public class Student {
    private String grade;
    private String clazz;
    private Person person;
    private Date birthDate;
    private LocalDate birthDate_;
    private List<String> listData;
}

<bean id="student" class="org.spring.Student">
    <property name="grade" value="1年级"/>
    <property name="clazz" value="2班"></property>
    <property name="person" ref="person"/>
    <property name="birthDate" value="2020-01-01"/>
    <property name="birthDate_" value="2020-01-01"/>
</bean>

测试代码:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-test.xml");
applicationContext.start();
Student student = applicationContext.getBean(Student.class);
System.out.println(student);
applicationContext.stop();

执行结果:

如果没有注册编辑器是无法将字符串"2020-01-01"赋值给字段birthDate和birthDate_的,程序将会报错。

==============接下来从源码分析调用逻辑=================
当spring容器genBean获取bean实例时,其实整个过程就是根据配置信息BeanDefinition创建bean实例的过程,
调用链路:

AbstractBeanFactory#getBean(java.lang.String)==》AbstractBeanFactory#doGetBean ==》AbstractAutowireCapableBeanFactory#createBean==》AbstractAutowireCapableBeanFactory#doCreateBean

AbstractAutowireCapableBeanFactory#doCreateBean是创建bean实例的核心:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {


    //需要分析的核心代码:节点1    目的用于创建bean实例
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            //创建BeanWrapper对象,BeanWrapper类至关重要
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

        // post-processors后置处理器,此处可以通过后置处理器修改容器中的BeandeDinition对象.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                mbd.postProcessed = true;
            }
        }

        // 解决spring bean循环依赖的. A依赖B,B依赖A, 先将A实例化(此时A只是刚刚实例化,属性还未赋值),然后将A放到Map本地缓存中,接着为A填充属性值。
        // 如果填充属性时发现需要B,此时需要通过getBean(B)获取B实例,步骤如A,先将B实例化,接着为B填充属性值,填充属性时发现需要A,getBean(A)获取A实例,此时的实例A就是来源于上面Map本地缓存
        //下面代码的逻辑就是将刚刚创建的Bean实例放到缓存中,用于解决循环依赖
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //需要分析的核心代码:节点2
            // 为Bean实例属性填充值
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            // ...异常代码(略)
        }

        // ...其它代码(略)

        return exposedObject;
    }


    //需要分析的核心代码:节点2
    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        PropertyValues pvs = mbd.getPropertyValues();

        // ...其它代码(略)

        //byName或者byType自动装配功能
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            /*
                public class A {
                    private String name;
                    private B b;
                }

                class B { }

                <bean id="a" class="XXX.XXX.A">
                    <property name="name" value="zhangsan"/>
                </bean>
                <bean id="b" class="XXX.XXX.B"></bean>
            */
            // 如上代码段,A实例中有字段类型为B,但是xml配置中<bean>并没有<property name="b" ref="b"/>
            //BeanWrapper通过反射寻找setXXX,获取XXX属性和BeanDefinition中的PropertyValues属性值名称对比
            //如果BeanDefinition中不包含属性名,则自动装配XXX属性,然后注入到BeanDefinition的PropertyValues中
            //属性名为XXX,属性值bean
  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值