Spring的强大之处不仅仅在于它为Java开发者提供了极大便利,更在于它的开放式架构,使得用户可以拥有最大扩展Spring的能力。
我们在xml定义bean时,输入的内容都是字符串。spring会根据已经注册好的属性编辑器解析这些字符串,实例化成对应的类型。
一,源码相关
1,创建默认的propertyEditorRegister
在AbstractApplicationContext的refresh()方法的prepareBeanFactory()方法中创建一个默认的PropertyEditorRegister放入beanFactory中,此类主要负责注入如下默认的属性编辑器:
public void registerCustomEditors(PropertyEditorRegistry registry) {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
doRegisterEditor(registry, Resource.class, baseEditor);
doRegisterEditor(registry, ContextResource.class, baseEditor);
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if (this.resourceLoader instanceof ResourcePatternResolver) {
doRegisterEditor(registry, Resource[].class,
new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
}
}
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if (registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
}
else {
registry.registerCustomEditor(requiredType, editor);
}
}
2,调用registerCustomEditors来完成PropertyEditor的注册
spring源码在实例化bean的时候,创建完BeanWrapperImpl之后会调用registerCustomEditors()方法来遍历所有的propertyEditorRegister(包括我们自定义的propertyEditorRegister)类来完成属性编辑器的注入。如下:
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
registerCustomEditors(bw);
}
3,调用PropertyEditor来完成属性的解析
在populateBean对属性填充时会遍历每一个属性值来获取对应的属性编辑器,然后调用对应的属性编辑器(PropertyEditor)的setAsText()方法来解析对应的值。
二,案例
Address.java
package com.bobo.customeditor;
/**
* @author bobo
* @date 2020-10-21
*/
public class Address {
private String province;
private String city;
private String area;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", area='" + area + '\'' +
'}';
}
}
Person.java
package com.bobo.customeditor;
/**
* @author bobo
* @date 2020-10-21
*/
public class Person {
private String name;
private Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", address=" + address +
'}';
}
}
AddressPropertyEditor
package com.bobo.customeditor;
import java.beans.PropertyEditorSupport;
/**
* @author bobo
* @date 2020-10-21
*/
public class AddressPropertyEdit extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] split = text.split("-");
Address address = new Address();
address.setProvince(split[0]);
address.setCity(split[1]);
address.setArea(split[2]);
setValue(address);
}
}
AddressPropertyEditorRegister.java
package com.bobo.customeditor;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
/**
* @author bobo
* @date 2020-10-21
*/
public class AddressPropertyEditorRegister implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Address.class,new AddressPropertyEdit());
}
}
application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.bobo.customeditor.Person">
<property name="name" value="bobo"/>
<property name="address" value="广东省-深圳市-南山区"/>
</bean>
<!--第一种方式-->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.bobo.customeditor.AddressPropertyEditorRegister"></bean>
</list>
</property>
</bean>
<!--第二种方式-->
<!-- <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">-->
<!-- <property name="customEditors">-->
<!-- <map>-->
<!-- <entry key="com.bobo.customeditor.Address">-->
<!-- <value>com.bobo.customeditor.AddressPropertyEdit</value>-->
<!-- </entry>-->
<!-- </map>-->
<!-- </property>-->
<!-- </bean>-->
</beans>
test.java
package com.bobo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
System.out.println(context.getBean("person"));
}
}
运行输出:
Person{
name='bobo', address=Address{
province='广东省', city='深圳市', area='南山区'}}