spring源码扩展点四:自定义属性编辑器PropertyEditor

it2024-08-01  39

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='南山区'}}
最新回复(0)