Spring 自定义属性解析器
【摘要】 《读尽源码 第三十篇》
用例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.huifer.source.spring.bean.DatePropertyRegister"/>
</list>
</property>
<property name="customEditors">
<map>
<entry key="java.util.Date" value="com.huifer.source.spring.bean.DatePropertyEditor">
</entry>
</map>
</property>
</bean>
<bean id="apple" class="com.huifer.source.spring.bean.Apple">
<property name="date" value="2020-01-01 01:01:01"/>
</bean>
</beans>Copy to clipboardErrorCopied
public class DatePropertyRegister implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(
new SimpleDateFormat("yyyy-MM-dd"), true)
);
}
}Copy to clipboardErrorCopied
public class DatePropertyEditor extends PropertyEditorSupport {
private String format = "yyyy-MM-dd";
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
System.out.println(text);
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date date = sdf.parse(text);
this.setValue(date);
} catch (Exception e) {
e.printStackTrace();
}
}
}Copy to clipboardErrorCopied
PropertyEditorRegistrar 解析
-
直接在DatePropertyRegister打上断点进行查看注册流程
直接看调用堆栈获取调用层次
@Override
public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
registerCustomEditor(requiredType, null, propertyEditor);
}
Copy to clipboardErrorCopied
@Override
public void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor) {
if (requiredType == null && propertyPath == null) {
throw new IllegalArgumentException("Either requiredType or propertyPath is required");
}
if (propertyPath != null) {
if (this.customEditorsForPath == null) {
this.customEditorsForPath = new LinkedHashMap<>(16);
}
this.customEditorsForPath.put(propertyPath, new CustomEditorHolder(propertyEditor, requiredType));
}
else {
if (this.customEditors == null) {
this.customEditors = new LinkedHashMap<>(16);
}
// 放入 customEditors map对象中
this.customEditors.put(requiredType, propertyEditor);
this.customEditorCache = null;
}
}
Copy to clipboardErrorCopied
-
PropertyEditorRegistrySupport
此处对象是通过DatePropertyRegister传递的
-
org.springframework.beans.factory.support.AbstractBeanFactory#registerCustomEditors
protected void registerCustomEditors(PropertyEditorRegistry registry) {
PropertyEditorRegistrySupport registrySupport =
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
if (registrySupport != null) {
registrySupport.useConfigValueEditors();
}
if (!this.propertyEditorRegistrars.isEmpty()) {
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
try {
/**
* {@link ResourceEditorRegistrar#registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)}或者
* {@link PropertyEditorRegistrar#registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)}
*/
registrar.registerCustomEditors(registry);
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
"] failed because it tried to obtain currently created bean '" +
ex.getBeanName() + "': " + ex.getMessage());
}
onSuppressedException(ex);
continue;
}
}
throw ex;
}
}
}
if (!this.customEditors.isEmpty()) {
this.customEditors.forEach((requiredType, editorClass) ->
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
}
}
Copy to clipboardErrorCopied
- void registerCustomEditors(PropertyEditorRegistry registry); 用例中编写的DatePropertyRegister正好有这个方法的实现
·
- 在AbstractBeanFactory中查看变量
-
为什么最后结果变成com.huifer.source.spring.bean.DatePropertyEditor
看配置文件
<property name="customEditors"> <map> <entry key="java.util.Date" value="com.huifer.source.spring.bean.DatePropertyEditor"> </entry> </map> </property> Copy to clipboardErrorCopied
-
对应的 set 方法
public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) { this.customEditors = customEditors; }Copy to clipboardErrorCopied
-
applyPropertyValues
-
应用属性值
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs.isEmpty()) { return; } if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } MutablePropertyValues mpvs = null; // 没有解析的属性 List<PropertyValue> original; if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; if (mpvs.isConverted()) { //MutablePropertyValues 对象中存在转换后对象直接赋值 // Shortcut: use the pre-converted values as-is. try { bw.setPropertyValues(mpvs); return; } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } original = mpvs.getPropertyValueList(); } else { original = Arrays.asList(pvs.getPropertyValues()); } // 自定义转换器 TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } // 创建BeanDefinitionValueResolver BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); // Create a deep copy, resolving any references for values. // 解析后的对象集合 List<PropertyValue> deepCopy = new ArrayList<>(original.size()); boolean resolveNecessary = false; for (PropertyValue pv : original) { // 解析过的属性 if (pv.isConverted()) { deepCopy.add(pv); } // 没有解析过的属性 else { // 属性名称 String propertyName = pv.getName(); // 属性值,直接读取到的 Object originalValue = pv.getValue(); // 解析值 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); Object convertedValue = resolvedValue; /** * 1. isWritableProperty: 属性可写 * 2. isNestedOrIndexedProperty: 是否循环嵌套 */ boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); if (convertible) { // 转换器解析 convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } // Possibly store converted value in merged bean definition, // in order to avoid re-conversion for every created bean instance. if (resolvedValue == originalValue) { if (convertible) { // 设置解析值 pv.setConvertedValue(convertedValue); } deepCopy.add(pv); } // 类型解析 else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); deepCopy.add(pv); } else { resolveNecessary = true; deepCopy.add(new PropertyValue(pv, convertedValue)); } } } if (mpvs != null && !resolveNecessary) { // 转换成功的标记方法 mpvs.setConverted(); } // Set our (possibly massaged) deep copy. try { bw.setPropertyValues(new MutablePropertyValues(deepCopy)); } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } Copy to clipboardErrorCopied
-
属性值解析
@Nullable private Object convertForProperty( @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) { if (converter instanceof BeanWrapperImpl) { return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName); } else { PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam); } } Copy to clipboardErrorCopied
private Object doConvertTextValue(@Nullable Object oldValue, String newTextValue, PropertyEditor editor) {
try {
editor.setValue(oldValue);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
}
// Swallow and proceed.
}
// 调用子类实现方法
editor.setAsText(newTextValue);
return editor.getValue();
}
Copy to clipboardErrorCopied
-
调用用例编写的方法
@Override public void setAsText(String text) throws IllegalArgumentException { System.out.println(text); SimpleDateFormat sdf = new SimpleDateFormat(format); try { Date date = sdf.parse(text); this.setValue(date); } catch (Exception e) { e.printStackTrace(); } } Copy to clipboardErrorCopied
该值也是这个方法的返回org.springframework.beans.TypeConverterDelegate#convertIfNecessary(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Class<T>, org.springframework.core.convert.TypeDescriptor)
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)