注入赋值
BeanWrapperImpl 類主要是對容器中完成初始化的Bean 實例對象進行屬性的依賴注入,即把Bean對象設(shè)置到它所依賴的另一個Bean 的屬性中去。然而,BeanWrapperImpl 中的注入方法實際上由AbstractNestablePropertyAccessor 來實現(xiàn)的,其相關(guān)源碼如下:
//實現(xiàn)屬性依賴注入功能 protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {if (tokens.keys != null) {processKeyedProperty(tokens, pv);}else {processLocalProperty(tokens, pv);} } //實現(xiàn)屬性依賴注入功能 @SuppressWarnings("unchecked") private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {//調(diào)用屬性的getter方法,獲取屬性的值Object propValue = getPropertyHoldingValue(tokens);PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);if (ph == null) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.actualName, "No property handler found");}Assert.state(tokens.keys != null, "No token keys");String lastKey = tokens.keys[tokens.keys.length - 1];//注入array類型的屬性值if (propValue.getClass().isArray()) {Class<?> requiredType = propValue.getClass().getComponentType();int arrayIndex = Integer.parseInt(lastKey);Object oldValue = null;try {if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {oldValue = Array.get(propValue, arrayIndex);}Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),requiredType, ph.nested(tokens.keys.length));//獲取集合類型屬性的長度int length = Array.getLength(propValue);if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {Class<?> componentType = propValue.getClass().getComponentType();Object newArray = Array.newInstance(componentType, arrayIndex + 1);System.arraycopy(propValue, 0, newArray, 0, length);setPropertyValue(tokens.actualName, newArray);//調(diào)用屬性的getter方法,獲取屬性的值propValue = getPropertyValue(tokens.actualName);}//將屬性的值賦值給數(shù)組中的元素Array.set(propValue, arrayIndex, convertedValue);}catch (IndexOutOfBoundsException ex) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Invalid array index in property path '" + tokens.canonicalName + "'", ex);}}//注入list類型的屬性值else if (propValue instanceof List) {//獲取list集合的類型Class<?> requiredType = ph.getCollectionType(tokens.keys.length);List<Object> list = (List<Object>) propValue;//獲取list集合的sizeint index = Integer.parseInt(lastKey);Object oldValue = null;if (isExtractOldValueForEditor() && index < list.size()) {oldValue = list.get(index);}//獲取list解析后的屬性值Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),requiredType, ph.nested(tokens.keys.length));int size = list.size();//如果list的長度大于屬性值的長度,則多余的元素賦值為nullif (index >= size && index < this.autoGrowCollectionLimit) {for (int i = size; i < index; i++) {try {list.add(null);}catch (NullPointerException ex) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Cannot set element with index " + index + " in List of size " +size + ", accessed using property path '" + tokens.canonicalName +"': List does not support filling up gaps with null elements");}}list.add(convertedValue);}else {try {//將值添加到list中l(wèi)ist.set(index, convertedValue);}catch (IndexOutOfBoundsException ex) {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Invalid list index in property path '" + tokens.canonicalName + "'", ex);}}}//注入map類型的屬性值else if (propValue instanceof Map) {//獲取map集合key的類型Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);//獲取map集合value的類型Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);Map<Object, Object> map = (Map<Object, Object>) propValue;// IMPORTANT: Do not pass full property name in here - property editors// must not kick in for map keys but rather only for map values.TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);//解析map類型屬性key值Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);Object oldValue = null;if (isExtractOldValueForEditor()) {oldValue = map.get(convertedMapKey);}// Pass full property name and old value in here, since we want full// conversion ability for map values.//解析map類型屬性value值Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),mapValueType, ph.nested(tokens.keys.length));//將解析后的key和value值賦值給map集合屬性map.put(convertedMapKey, convertedMapValue);}else {throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Property referenced in indexed property path '" + tokens.canonicalName +"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");} } private Object getPropertyHoldingValue(PropertyTokenHolder tokens) {// Apply indexes and map keys: fetch value for all keys but the last one.Assert.state(tokens.keys != null, "No token keys");PropertyTokenHolder getterTokens = new PropertyTokenHolder(tokens.actualName);getterTokens.canonicalName = tokens.canonicalName;getterTokens.keys = new String[tokens.keys.length - 1];System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);Object propValue;try {//獲取屬性值propValue = getPropertyValue(getterTokens);}catch (NotReadablePropertyException ex) {throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,"Cannot access indexed value in property referenced " +"in indexed property path '" + tokens.canonicalName + "'", ex);}if (propValue == null) {// null map value caseif (isAutoGrowNestedPaths()) {int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);propValue = setDefaultValue(getterTokens);}else {throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,"Cannot access indexed value in property referenced " +"in indexed property path '" + tokens.canonicalName + "': returned null");}}return propValue; }通過對上面注入依賴代碼的分析,我們已經(jīng)明白了Spring IOC 容器是如何將屬性的值注入到Bean 實例對象中去的:
1)、對于集合類型的屬性,將其屬性值解析為目標類型的集合后直接賦值給屬性。
2)、對于非集合類型的屬性,大量使用了JDK 的反射機制,通過屬性的getter()方法獲取指定屬性注入以前的值,同時調(diào)用屬性的setter()方法為屬性設(shè)置注入后的值。看到這里相信很多人都明白了Spring的setter()注入原理。
至此Spring IOC 容器對Bean 定義資源文件的定位,載入、解析和依賴注入已經(jīng)全部分析完畢,現(xiàn)在Spring IOC 容器中管理了一系列靠依賴關(guān)系聯(lián)系起來的Bean,程序不需要應(yīng)用自己手動創(chuàng)建所需的對象,Spring IOC 容器會在我們使用的時候自動為我們創(chuàng)建,并且為我們注入好相關(guān)的依賴,這就是Spring 核心功能的控制反轉(zhuǎn)和依賴注入的相關(guān)功能。
?
總結(jié)
- 上一篇: 解析属性注入规则
- 下一篇: IOC 容器中那些鲜为人知的细节