The power of Spring is not only that it provides great convenience for Java developers, but also that its open architecture allows users to have the greatest ability to extend Spring.
When we define bean in xml, the input content is all strings. Spring will parse these strings according to the registered property editor and instantiate them into the corresponding type.
One, source code related
1. Create a default propertyEditorRegister
Create a default PropertyEditorRegister in the prepareBeanFactory() method of the refresh() method of AbstractApplicationContext and put it into the beanFactory. This class is mainly responsible for injecting the following default property editors:
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. Call registerCustomEditors to complete the registration of PropertyEditor
When the spring source code instantiates the bean, after the BeanWrapperImpl is created, the registerCustomEditors() method is called to traverse all the propertyEditorRegister (including our custom propertyEditorRegister) classes to complete the injection of the property editor. as follows:
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
registerCustomEditors(bw);
}
3. Call PropertyEditor to complete the analysis of properties
When populateBean fills in the properties, it will traverse each property value to obtain the corresponding property editor, and then call the setAsText() method of the corresponding property editor (PropertyEditor) to parse the corresponding value.
Second, the case
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"));
}
}
Run output:
Person{
name='bobo', address=Address{
province='广东省', city='深圳市', area='南山区'}}