diff --git a/docs/Spring/clazz/Spring-Custom-attribute-resolver.md b/docs/Spring/clazz/Spring-Custom-attribute-resolver.md new file mode 100644 index 0000000..25e5932 --- /dev/null +++ b/docs/Spring/clazz/Spring-Custom-attribute-resolver.md @@ -0,0 +1,403 @@ +# Spring 自定义属性解析器 +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读仓库: [huifer-spring](https://github.com/huifer/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)` + diff --git a/docs/Spring/clazz/Spring-OrderUtils.md b/docs/Spring/clazz/Spring-OrderUtils.md new file mode 100644 index 0000000..f67872e --- /dev/null +++ b/docs/Spring/clazz/Spring-OrderUtils.md @@ -0,0 +1,62 @@ +# Spring OrderUtils +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework-read) +- `org.springframework.core.annotation.OrderUtils`主要方法如下 + 1. getOrder + 1. getPriority + +- 测试类`org.springframework.core.annotation.OrderUtilsTests` + +```java + @Nullable + public static Integer getOrder(Class type) { + // 缓存中获取 + Object cached = orderCache.get(type); + if (cached != null) { + // 返回 int + return (cached instanceof Integer ? (Integer) cached : null); + } + /** + * 注解工具类,寻找{@link Order}注解 + */ + Order order = AnnotationUtils.findAnnotation(type, Order.class); + Integer result; + if (order != null) { + // 返回 + result = order.value(); + } else { + result = getPriority(type); + } + // key: 类名,value: intValue + orderCache.put(type, (result != null ? result : NOT_ANNOTATED)); + return result; + } + +``` + + +```java + @Nullable + public static Integer getPriority(Class type) { + if (priorityAnnotationType == null) { + return null; + } + // 缓存中获取 + Object cached = priorityCache.get(type); + if (cached != null) { + // 不为空返回 + return (cached instanceof Integer ? (Integer) cached : null); + } + // 注解工具获取注解 + Annotation priority = AnnotationUtils.findAnnotation(type, priorityAnnotationType); + Integer result = null; + if (priority != null) { + // 获取 value + result = (Integer) AnnotationUtils.getValue(priority); + } + // 向缓存插入数据 + priorityCache.put(type, (result != null ? result : NOT_ANNOTATED)); + return result; + } + +``` \ No newline at end of file diff --git a/images/spring/image-20200117104710142.png b/images/spring/image-20200117104710142.png new file mode 100644 index 0000000..aca0d46 Binary files /dev/null and b/images/spring/image-20200117104710142.png differ diff --git a/images/spring/image-20200117110115741.png b/images/spring/image-20200117110115741.png new file mode 100644 index 0000000..2c42c2b Binary files /dev/null and b/images/spring/image-20200117110115741.png differ diff --git a/images/spring/image-20200117110846256.png b/images/spring/image-20200117110846256.png new file mode 100644 index 0000000..0f5b781 Binary files /dev/null and b/images/spring/image-20200117110846256.png differ diff --git a/images/spring/image-20200117111131406.png b/images/spring/image-20200117111131406.png new file mode 100644 index 0000000..8e092a2 Binary files /dev/null and b/images/spring/image-20200117111131406.png differ diff --git a/images/spring/image-20200117133325461.png b/images/spring/image-20200117133325461.png new file mode 100644 index 0000000..6e35c95 Binary files /dev/null and b/images/spring/image-20200117133325461.png differ diff --git a/images/spring/image-20200117141309038.png b/images/spring/image-20200117141309038.png new file mode 100644 index 0000000..781b163 Binary files /dev/null and b/images/spring/image-20200117141309038.png differ diff --git a/images/spring/image-20200117141519123.png b/images/spring/image-20200117141519123.png new file mode 100644 index 0000000..ddbb8b9 Binary files /dev/null and b/images/spring/image-20200117141519123.png differ diff --git a/images/spring/image-20200117142800671.png b/images/spring/image-20200117142800671.png new file mode 100644 index 0000000..9706882 Binary files /dev/null and b/images/spring/image-20200117142800671.png differ diff --git a/images/spring/image-20200117143022827.png b/images/spring/image-20200117143022827.png new file mode 100644 index 0000000..92eabae Binary files /dev/null and b/images/spring/image-20200117143022827.png differ