# Spring 自定义属性解析器 - Author: [HuiFer](https://github.com/huifer) - 源码阅读仓库: [SourceHot-Spring](https://github.com/SourceHot/spring-framework-read) ## 用例 ```xml ``` ```java public class DatePropertyRegister implements PropertyEditorRegistrar { @Override public void registerCustomEditors(PropertyEditorRegistry registry) { registry.registerCustomEditor(Date.class, new CustomDateEditor( new SimpleDateFormat("yyyy-MM-dd"), true) ); } } ``` ```java 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(); } } } ``` ## PropertyEditorRegistrar解析 - 直接在`DatePropertyRegister`打上断点进行查看注册流程 ![image-20200117104710142](../../../images/spring/image-20200117104710142.png) 直接看调用堆栈获取调用层次 ```java @Override public void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor) { registerCustomEditor(requiredType, null, propertyEditor); } ``` ```java @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; } } ``` - `PropertyEditorRegistrySupport` ![image-20200117111131406](../../../images/spring/image-20200117111131406.png) 此处对象是通过`DatePropertyRegister`传递的 - `org.springframework.beans.factory.support.AbstractBeanFactory#registerCustomEditors` ```java 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))); } } ``` - `void registerCustomEditors(PropertyEditorRegistry registry);` 用例中编写的`DatePropertyRegister`正好有这个方法的实现 · - 在`AbstractBeanFactory`中查看变量 ![image-20200117110115741](../../../images/spring/image-20200117110115741.png) - 为什么最后结果变成`com.huifer.source.spring.bean.DatePropertyEditor` 看配置文件 ```xml ``` - 对应的set方法 ```java public void setCustomEditors(Map, Class> customEditors) { this.customEditors = customEditors; } ``` ![image-20200117110846256](../../../images/spring/image-20200117110846256.png) ## applyPropertyValues - 应用属性值 ```java 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 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 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); } } ``` ![image-20200117133325461](../../../images/spring/image-20200117133325461.png) ![image-20200117141309038](../../../images/spring/image-20200117141309038.png) ![image-20200117141519123](../../../images/spring/image-20200117141519123.png) - 属性值解析 ![image-20200117142800671](../../../images/spring/image-20200117142800671.png) ```JAVA @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); } } ``` ```JAVA 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(); } ``` - 调用用例编写的方法 ```JAVA @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(); } } ``` ![image-20200117143022827](../../../images/spring/image-20200117143022827.png) 该值也是这个方法的返回`org.springframework.beans.TypeConverterDelegate#convertIfNecessary(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Class, org.springframework.core.convert.TypeDescriptor)`