属性编辑器
学校小故事
为了了解spring流程,需要接受、了解、熟悉很多未知的定义,在此使用 学校 作为辅助,帮助我们了解spring。
<此版本中 新增BeanFactoryPostProcessor>
学校 | spring |
---|---|
学校管理局 | spring开发人员 |
学校信息 | ApplicationContext |
学校人员信息库 | DefaultListableBeanFactory |
学校人员属性编辑器库 | AbstractBeanFactory中的propertyEditorRegistrars |
校内人员信息 | Map<name,BeanDefinitionMap> BeanDefinitionMap |
校内人员名称 | BeanDefinitionNames |
第三方服务公司<非学生信息服务> | BeanFactoryPostProcessor |
属性编辑器第三方公司 | CustomEditorConfigurer |
第三方服务公司<学生信息服务> | BeanDefinitionRegistryPostProcessor |
人员 | bean |
人员信息 | BeanDefinition |
处理问题场景
学校需要收集学生个人信息,完成信息维护。学生带着信息:出生日期<2020-01-03>,出生地址<A省-B市-C区>,学生当前年龄<10>
学校:这个信息全是字符串,我只想专注于建校+接学生老师,其他工作不在我的只能范围内。
学校管理局:这个工作可以交给第三方服务公司处理,它就是做这个工作的。
第三方服务公司<BeanFactoryPostProcessor类>:这个我可以解决,我将所有的属性编辑器初始化后 为学生实例赋值中。
属性编辑器库
BeanFactory中的属性编辑器库
学校人员属性编辑器库
AbstractBeanFactory中的
propertyEditorRegistrars属性
系统自定义属性编辑器注册器
<不唯一,可以自定义模仿 CustomEditorConfigurer实现功能>
CustomEditorConfigurer类中的
postProcessBeanFactory方法<向BeanFactory中注册属性编辑器>
系统自定义属性编辑器注册器初始化
spring十三太保之三<prepareBeanFactory方法>中完成初始化。
AbstractApplicationContext类中的
prepareBeanFactory方法
// 完成属性编辑器的
635行:beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
系统自定义属性编辑器注册器 注册属性编辑器
spring十三太保之五<invokeBeanFactoryPostProcessors方法>中完成注册。
PostProcessorRegistrationDelegate类中的
invokeBeanFactoryPostProcessors方法
// 执行CustomEditorConfigurer<BeanFactoryPostProcessor>中的postProcessBeanFactory方法
// 在 BeanFactory 中的 propertyEditorRegistrars属性中注册 自定义属性编辑器
174行:invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
属性编辑器使用
spring十三太保之十一<finishBeanFactoryInitialization方法>中完成初始化及调用处理。
在spring中bean对象创建分为三部分:实例化、赋值、初始化init方法执行。
属性编辑器一般在赋值阶段完成初始化 + 使用。
属性编辑器有两种:系统默认创建的属性编辑器,自定义属性编辑器。
属性编辑器实例化
doCreateBean方法中的
538行:instanceWrapper = createBeanInstance(beanName, mbd, args); 中完成属性编辑器实例化
执行到 instantiateBean 方法时,
1264行:BeanWrapper bw = new BeanWrapperImpl(beanInstance); 中完成默认属性编辑器的注册
1265行:initBeanWrapper(bw); 中完成自定义属性编辑器的注册
属性编辑器自定义编辑属性
以下是代码中的关键节点,按节点 debug 可以查看关键节点处,bean属性赋值情况。
其中:1、2、3、4、5、6、7、9属于流程节点;8、10属于关键debug节点。
1、doCreateBean方法中的
575行:populateBean(beanName, mbd, instanceWrapper); 中开始赋值
2、populateBean方法中的
1400行:applyPropertyValues(beanName, mbd, bw, pvs);
3、applyPropertyValues方法中的
1653行:convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
4、convertForProperty方法中的
1697行:return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
5、convertForProperty方法中的
219行:return convertForProperty(propertyName, null, value, td);
6、convertForProperty方法中的
604行:return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
7、convertIfNecessary方法中的
585行:return this.typeConverterDelegate.convertIfNecessary(******);
8、convertIfNecessary方法中的
// 根据属性class类型,筛选属性编辑器
156行:PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
// 使用属性编辑器,完成目标bean属性 的转换服务
192行:convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
9、doConvertValue方法中的
439行:return doConvertTextValue(oldValue, newTextValue, editor);
10、doConvertTextValue方法中的
466行:editor.setAsText(newTextValue); // 自定义 属性编辑器的重新方法,String 转为Object,完成属性赋值
自定义实现属性编辑器
0、明确需要编辑属性+编辑属性目标
以学生、地址为例
// Student.class 编辑属性目标
@Data
public class Student {
private String name;
private Address address; // 需要编辑属性
private String age;
}
// Address.class
@Data
public class Address { // 需要编辑属性
private String province;
private String city;
private String town;
}
1、创建自定义属性编辑器
// AddressPropertyEditor.class
public class AddressPropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] s = text.split("-");
Address address = new Address();
address.setProvince(s[0]);
address.setCity(s[1]);
address.setTown(s[2]);
setValue(address);
}
}
2、自定义属性编辑注册器,实现PropertyEditorRegistrar接口
// AddressPropertyEditorRegistrar.class
public class AddressPropertyEditorRegistrar implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Address.class, new AddressPropertyEditor());
}
}
3、使spring识别自定义属性编辑器<xml文件配置>
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">
<!-- spring管理 有需要属性编辑器处理属性 的类 -->
<bean id="student" class="com.spring.cloud.moduletest.property.editor.Student">
<property name="name" value="test"></property>
<property name="address" value="A省-B市-C区"></property>
<property name="age" value="10"></property>
</bean>
<!-- 自定义属性编辑器库中,注册自定义编辑器 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<array>
<bean class="com.spring.cloud.moduletest.property.editor.AddressPropertyEditorRegistrar"></bean>
</array>
</property>
</bean>
</beans>
4、启动和结果
public class PropertyEditorSpringStart {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("property/editor/propertyEditor.xml");
Student student = ac.getBean(Student.class);
System.out.println(student.getName());
System.out.println(student.getAddress());
System.out.println(student.getAge());
}
/**
* 输出结果:
* 启动日志省略
* test
* Address(province=A省, city=B市, town=C区)
* 10
*/
}