自定义属性编辑器有两种方式
第一种方式:
<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