Spring 系列目錄(http://www.javashuo.com/article/p-hskusway-em.html)html
BeanWrapper 有兩個核心的實現類java
AbstractNestablePropertyAccessor
提供對嵌套屬性的支持BeanWrapperImpl
提供對 JavaBean 的內省功能,如 PropertyDescriptorAbstractNestablePropertyAccessor 是 Spring 4.2 提供的功能,將原 BeanWrapperImpl 的功能抽出,這樣 BeanWrapperImpl 只提供對 JavaBean 的內省功能。算法
AbstractNestablePropertyAccessor 類經過其成員屬性提供了一種支持嵌套屬性的數據結構,下面是幾個核心的的屬性成員:spring
屬性類型及名稱 | 說明 |
---|---|
Object object | 被 BeanWrapper 包裝的對象 |
String nestedPath | 當前 BeanWrapper 對象所屬嵌套層次的屬性名,最頂層的 BeanWrapper 此屬性的值爲空 |
Object rootObject | 最頂層 BeanWrapper 所包裝的對象 |
Map nestedBeanWrappers | 緩存當前 BeanWrapper 的嵌套屬性的 nestedPath 和對應的 BeanWrapperImpl 對象 |
例如以下的類結構:數組
@Test public void test() throws Exception { BeanWrapperImpl rootBeanWrapper = new BeanWrapperImpl(Company.class); rootBeanWrapper.setAutoGrowNestedPaths(true); rootBeanWrapper.setPropertyValue("name", "company"); rootBeanWrapper.setPropertyValue("department.name", "company"); rootBeanWrapper.setPropertyValue("director.info.name", "info..."); rootBeanWrapper.setPropertyValue("employees[0].attrs['a']", "a"); } public class Company { private String name; private int total; private Department department; private Employee director; private Employee[] employees; private Map<Department, List<Employee>> departmentEmployees; public static class Employee { private String name; private double salary; private Map<String, String> attrs; } public static class Department { private String name; } }
rootBeanWrapper 各嵌套層的屬性以下:緩存
對象 | level | object | nestedPath | rootObject | nestedBeanWrappers |
---|---|---|---|---|---|
rootBeanWrapper | 0(根) | company | "" | company | department -> departmentBeanWrapper director -> directorBeanWrapper |
departmentBeanWrapper | 1 | department | department | company | 無 |
directorBeanWrapper | 1 | director | director | company | info -> infoBeanWrapper |
infoBeanWrapper | 2 | info | director.info | company | 無 |
getPropertyAccessorForPropertyPath 根據屬性(propertyPath)獲取所在 bean 的包裝對象 beanWrapper。若是是相似 director.info.name 的嵌套屬性,則須要遞歸獲取。真正獲取指定屬性的包裝對象則由方法 getNestedPropertyAccessor 完成。數據結構
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) { // 1. 獲取第一個點以前的屬性部分。eg: director.info.name 返回 department int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath); // 2. 遞歸處理嵌套屬性 // 2.1 先獲取 director 屬性所在類的 rootBeanWrapper // 2.2 再獲取 info 屬性所在類的 directorBeanWrapper // 2.3 依此類推,獲取最後一個屬性 name 屬性所在類的 infoBeanWrapper if (pos > -1) { String nestedProperty = propertyPath.substring(0, pos); String nestedPath = propertyPath.substring(pos + 1); AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty); return nestedPa.getPropertyAccessorForPropertyPath(nestedPath); // 3. 當前對象直接返回 } else { return this; } }
getPropertyAccessorForPropertyPath 有兩種狀況:app
director(不包含 .)
直接返回當前 bean 的包裝對象director.info.name(包含 .)
從當前對象開始遞歸查找,root -> director -> info。查找當前 beanWrapper 指定屬性的包裝對象由方法 getNestedPropertyAccessor 完成。// 緩存已經查找事後 AbstractNestablePropertyAccessor private Map<String, AbstractNestablePropertyAccessor> nestedPropertyAccessors; private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) { if (this.nestedPropertyAccessors == null) { this.nestedPropertyAccessors = new HashMap<>(); } // 1. 獲取屬性對應的 token 值,主要用於解析 attrs['key'][0] 這樣 Map/Array/Collection 循環嵌套的屬性 PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty); String canonicalName = tokens.canonicalName; Object value = getPropertyValue(tokens); // 2. 屬性不存在則根據 autoGrowNestedPaths 決定是否自動建立 if (value == null || (value instanceof Optional && !((Optional) value).isPresent())) { if (isAutoGrowNestedPaths()) { value = setDefaultValue(tokens); } else { throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName); } } // 3. 先從緩存中獲取,沒有就建立一個新的 nestedPa AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName); if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) { nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR); // Inherit all type-specific PropertyEditors. copyDefaultEditorsTo(nestedPa); copyCustomEditorsTo(nestedPa, canonicalName); this.nestedPropertyAccessors.put(canonicalName, nestedPa); } return nestedPa; }
getNestedPropertyAccessor 方法使用了動態規劃算法,緩存每次遞歸的查的結果。該方法獲取當前 bean 指定屬性(nestedProperty)對應的 AbstractNestablePropertyAccessor。固然這個屬性可能爲 attrs['key'][0] 類型,這樣就須要處理 Array、Map、List、Set 這樣的數據類型。PropertyTokenHolder 正是處理這種類型的屬性。ide
PropertyTokenHolder 用於解析嵌套屬性名稱,標識惟一的屬性。由於相似 attrs['key'][0] 這樣的屬性不統一,解析後將 [] 之間的 '
和 "
去除後保存在 canonicalName 中,attrs 保存在 actualName 中,["key", "0"] 保存在 keys 中。學習
protected static class PropertyTokenHolder { // 對應 bean 中的屬性名稱,如嵌套屬性 attrs['key'][0] 在 bean 中的屬性名稱爲 attrs public String actualName; // 將原始的嵌套屬性處理成標準的 token,如 attrs['key'][0] 處理成 attrs[key][0] public String canonicalName; // 這個數組存放的是嵌套屬性 [] 中的內容,如 attrs['key'][0] 處理成 ["key", "0"] public String[] keys;
屬性解析過程以下:
private PropertyTokenHolder getPropertyNameTokens(String propertyName) { String actualName = null; List<String> keys = new ArrayList<>(2); int searchIndex = 0; while (searchIndex != -1) { int keyStart = propertyName.indexOf(PROPERTY_KEY_PREFIX, searchIndex); searchIndex = -1; if (keyStart != -1) { int keyEnd = propertyName.indexOf(PROPERTY_KEY_SUFFIX, keyStart + PROPERTY_KEY_PREFIX.length()); if (keyEnd != -1) { // 1. actualName 對應 bean 中的屬性名稱 if (actualName == null) { actualName = propertyName.substring(0, keyStart); } // 2. 刪除每一個 key 中間的單引和雙引 String key = propertyName.substring(keyStart + PROPERTY_KEY_PREFIX.length(), keyEnd); if (key.length() > 1 && (key.startsWith("'") && key.endsWith("'")) || (key.startsWith("\"") && key.endsWith("\""))) { key = key.substring(1, key.length() - 1); } keys.add(key); searchIndex = keyEnd + PROPERTY_KEY_SUFFIX.length(); } } } PropertyTokenHolder tokens = new PropertyTokenHolder(actualName != null ? actualName : propertyName); if (!keys.isEmpty()) { // 3. canonicalName 爲原始屬性名稱去除單引和雙引以後的名稱 tokens.canonicalName += PROPERTY_KEY_PREFIX + StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) + PROPERTY_KEY_SUFFIX; tokens.keys = StringUtils.toStringArray(keys); } return tokens; }
PropertyHandler 的默認實現是 BeanPropertyHandler,位於 BeanWrapperImple 內,BeanPropertyHandler 是對 PropertyDescriptor 的封裝,提供了對 JavaBean 底層的操做,如屬性的讀寫。
protected PropertyHandler getPropertyHandler(String propertyName) throws BeansException { Assert.notNull(propertyName, "Property name must not be null"); AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName); return nestedPa.getLocalPropertyHandler(getFinalPath(nestedPa, propertyName)); } // PropertyHandler 是對 PropertyDescriptor 的封裝,提供了對 JavaBean 底層的操做,如屬性的讀寫 protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) { PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName); return (pd != null ? new BeanPropertyHandler(pd) : null); }
@Override public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException { // 1. 遞歸獲取 propertyName 屬性所在的 beanWrapper,如 director.info.name 獲取 name 屬性所在的 info bean AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName); // 2. 獲取屬性的 token PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); // 3. 設置屬性值 nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value)); }
setPropertyValue 分如下步驟:
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { // 1. Array、Map、List、Set 類型屬性注入。employees[0].attrs['a'] if (tokens.keys != null) { processKeyedProperty(tokens, pv); // 2. 簡單 bean 屬性注入。director } else { processLocalProperty(tokens, pv); } }
以 processLocalProperty 爲例屬性注入代碼以下:
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) { PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); if (ph == null || !ph.isWritable()) { // 處理 null 狀況 ... } Object oldValue = null; Object originalValue = pv.getValue(); Object valueToApply = originalValue; if (!Boolean.FALSE.equals(pv.conversionNecessary)) { if (pv.isConverted()) { valueToApply = pv.getConvertedValue(); } else { // 1. 將 oldValue 暴露給 PropertyEditor if (isExtractOldValueForEditor() && ph.isReadable()) { oldValue = ph.getValue(); } // 2. 類型轉換,委託給 TypeConverterDelegate 完成 valueToApply = convertForProperty( tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor()); } pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); } // 3. 屬性賦值 ph.setValue(valueToApply); }
getPropertyValue 根據屬性名稱獲取對應的值。
@Override public Object getPropertyValue(String propertyName) throws BeansException { AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName); PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); return nestedPa.getPropertyValue(tokens); } protected Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException { String propertyName = tokens.canonicalName; String actualName = tokens.actualName; PropertyHandler ph = getLocalPropertyHandler(actualName); if (ph == null || !ph.isReadable()) { throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName); } // 1. 反射獲取屬性對應的值 Object value = ph.getValue(); // 2. Array、Map、List、Set 類型須要單獨處理 if (tokens.keys != null) { if (value == null) { if (isAutoGrowNestedPaths()) { value = setDefaultValue(new PropertyTokenHolder(tokens.actualName)); } else { throw new NullValueInNestedPathException(); } } StringBuilder indexedPropertyName = new StringBuilder(tokens.actualName); // apply indexes and map keys for (int i = 0; i < tokens.keys.length; i++) { String key = tokens.keys[i]; if (value == null) { throw new NullValueInNestedPathException(); } else if (value.getClass().isArray()) { int index = Integer.parseInt(key); value = growArrayIfNecessary(value, index, indexedPropertyName.toString()); value = Array.get(value, index); } else if (value instanceof List) { int index = Integer.parseInt(key); List<Object> list = (List<Object>) value; growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1); value = list.get(index); } else if (value instanceof Set) { Set<Object> set = (Set<Object>) value; int index = Integer.parseInt(key); if (index < 0 || index >= set.size()) { throw new InvalidPropertyException(); } Iterator<Object> it = set.iterator(); for (int j = 0; it.hasNext(); j++) { Object elem = it.next(); if (j == index) { value = elem; break; } } } else if (value instanceof Map) { Map<Object, Object> map = (Map<Object, Object>) value; Class<?> mapKeyType = ph.getResolvableType().getNested(i + 1).asMap().resolveGeneric(0); TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType); Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); value = map.get(convertedMapKey); } indexedPropertyName.append(PROPERTY_KEY_PREFIX).append(key).append(PROPERTY_KEY_SUFFIX); } } return value; }
setDefaultValue 嵌套屬性爲 null 時設置默認屬性。
getPropertyAccessorForPropertyPath 遞歸獲取嵌套屬性,或 getPropertyValue 時,若是屬性爲 null 且 autoGrowNestedPaths=true 會建立默認的對象。如 director.info.name 時 director 爲 null 會調用其無參構造方法建立默認對象。
private Object setDefaultValue(PropertyTokenHolder tokens) { PropertyValue pv = createDefaultPropertyValue(tokens); setPropertyValue(tokens, pv); Object defaultValue = getPropertyValue(tokens); Assert.state(defaultValue != null, "Default value must not be null"); return defaultValue; } private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) { TypeDescriptor desc = getPropertyTypeDescriptor(tokens.canonicalName); Object defaultValue = newValue(desc.getType(), desc, tokens.canonicalName); return new PropertyValue(tokens.canonicalName, defaultValue); } // 建立一個默認的對象,type 爲 Class 類型,desc 用於解析集合或 Map 的泛型類型 private Object newValue(Class<?> type, @Nullable TypeDescriptor desc, String name) { // 1. Array 僅考慮二維數組 String[][] if (type.isArray()) { Class<?> componentType = type.getComponentType(); // TODO - only handles 2-dimensional arrays if (componentType.isArray()) { Object array = Array.newInstance(componentType, 1); Array.set(array, 0, Array.newInstance(componentType.getComponentType(), 0)); return array; } else { return Array.newInstance(componentType, 0); } // 2. Collection CollectionFactory.createCollection 都沒有指定泛型 } else if (Collection.class.isAssignableFrom(type)) { TypeDescriptor elementDesc = (desc != null ? desc.getElementTypeDescriptor() : null); return CollectionFactory.createCollection(type, (elementDesc != null ? elementDesc.getType() : null), 16); // 3. Map } else if (Map.class.isAssignableFrom(type)) { TypeDescriptor keyDesc = (desc != null ? desc.getMapKeyTypeDescriptor() : null); return CollectionFactory.createMap(type, (keyDesc != null ? keyDesc.getType() : null), 16); // 3. 簡單的 Bean,直接使用默認的無參構造方法 } else { Constructor<?> ctor = type.getDeclaredConstructor(); if (Modifier.isPrivate(ctor.getModifiers())) { throw new IllegalAccessException("Auto-growing not allowed with private constructor: " + ctor); } return BeanUtils.instantiateClass(ctor); } }
參考:
天天用心記錄一點點。內容也許不重要,但習慣很重要!