前言:上一篇講到了populateBean方法對Bean屬性的依賴注入,此篇繼續後面的內容。 數組
7.BeanDefinitionValueResolver解析屬性值 app
當容器在對屬性進行依賴注入時,若是發現屬性值須要進行類型轉換,好比屬性值是容器中另外一個Bean實例對象的引用, 則容器首先須要根據屬性值解析出所引用的對象,而後才能將該引用對象注入到目標實例對象的屬性上去,對屬性進行解析由resolveValueIfNecessary方法實現,源碼以下:ui
//解析屬性值,對注入類型進行轉換 @Nullable public Object resolveValueIfNecessary(Object argName, @Nullable Object value) { //對引用類型的屬性進行解析 if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; //調用引用類型屬性的解析方法 return resolveReference(argName, ref); } //對屬性值是引用容器中另外一個Bean名稱的解析 else if (value instanceof RuntimeBeanNameReference) { String refName = ((RuntimeBeanNameReference) value).getBeanName(); refName = String.valueOf(doEvaluate(refName)); //從容器中獲取指定名稱的Bean if (!this.beanFactory.containsBean(refName)) { throw new BeanDefinitionStoreException( "Invalid bean name '" + refName + "' in bean reference for " + argName); } return refName; } //對Bean類型屬性的解析,主要是Bean中的內部類 else if (value instanceof BeanDefinitionHolder) { // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases. BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); } else if (value instanceof BeanDefinition) { BeanDefinition bd = (BeanDefinition) value; String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(bd); return resolveInnerBean(argName, innerBeanName, bd); } //對集合數組類型的屬性解析 else if (value instanceof ManagedArray) { ManagedArray array = (ManagedArray) value; Class<?> elementType = array.resolvedElementType; if (elementType == null) { //獲取數組元素的類型 String elementTypeName = array.getElementTypeName(); if (StringUtils.hasText(elementTypeName)) { try { //使用反射機制建立指定類型的對象 elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); array.resolvedElementType = elementType; } catch (Throwable ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, ex); } } //沒有獲取到數組的類型,也沒有獲取到數組元素的類型 //則直接設置數組的類型爲Object else { elementType = Object.class; } } //建立指定類型的數組 return resolveManagedArray(argName, (List<?>) value, elementType); } //解析list類型的屬性值 else if (value instanceof ManagedList) { return resolveManagedList(argName, (List<?>) value); } //解析set類型的屬性值 else if (value instanceof ManagedSet) { return resolveManagedSet(argName, (Set<?>) value); } //解析map類型的屬性值 else if (value instanceof ManagedMap) { return resolveManagedMap(argName, (Map<?, ?>) value); } //解析props類型的屬性值,props其實就是key和value均爲字符串的map else if (value instanceof ManagedProperties) { Properties original = (Properties) value; //建立一個拷貝,用於做爲解析後的返回值 Properties copy = new Properties(); original.forEach((propKey, propValue) -> { if (propKey instanceof TypedStringValue) { propKey = evaluate((TypedStringValue) propKey); } if (propValue instanceof TypedStringValue) { propValue = evaluate((TypedStringValue) propValue); } if (propKey == null || propValue == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting Properties key/value pair for " + argName + ": resolved to null"); } copy.put(propKey, propValue); }); return copy; } //解析字符串類型的屬性值 else if (value instanceof TypedStringValue) { TypedStringValue typedStringValue = (TypedStringValue) value; Object valueObject = evaluate(typedStringValue); try { //獲取屬性的目標類型 Class<?> resolvedTargetType = resolveTargetType(typedStringValue); if (resolvedTargetType != null) { //對目標類型的屬性進行解析,遞歸調用 return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); } //沒有獲取到屬性的目標對象,則按Object類型返回 else { return valueObject; } } catch (Throwable ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex); } } else if (value instanceof NullBean) { return null; } else { return evaluate(value); } } //解析引用類型的屬性值 @Nullable private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { Object bean; //獲取引用的Bean名稱 String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); //若是引用的對象在父類容器中,則從父類容器中獲取指定的引用對象 if (ref.isToParent()) { if (this.beanFactory.getParentBeanFactory() == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Can't resolve reference to bean '" + refName + "' in parent factory: no parent factory available"); } bean = this.beanFactory.getParentBeanFactory().getBean(refName); } //從當前的容器中獲取指定的引用Bean對象,若是指定的Bean沒有被實例化,則會遞歸觸發引用Bean的初始化和依賴注入 else { bean = this.beanFactory.getBean(refName); //將當前實例化對象的依賴引用對象 this.beanFactory.registerDependentBean(refName, this.beanName); } if (bean instanceof NullBean) { bean = null; } return bean; } catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); } }
分析可知Spring是如何將引用類型,內部類以及集合類型等屬性進行解析的,屬性值解析完成後就能夠進行依賴注入了,依賴注入的過程就是Bean對象實例設置到它所依賴的Bean對象屬性上去,依賴注入是經過bw.setPropertyValues方法實現的,該方法也使用了委託模式,
在BeanWrapper接口中定義了方法聲明,依賴注入的具體實現交由其實現類BeanWrapperImpl來完成,接下來分析BeanWrapperImpl中依賴注入相關的源碼。 this
8.BeanWrapperImpl對Bean屬性的依賴注入 lua
BeanWrapperImpl類主要是對容器中完成初始化的Bean實例對象進行屬性的依賴注入,即把Bean對象設置到它所依賴的另外一個Bean的屬性中去。
BeanWrapperImpl中的注入方法由AbstractNestablePropertyAccessor來實現,源碼以下:code
//實現屬性依賴注入功能 protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { if (tokens.keys != null) { processKeyedProperty(tokens, pv); } else { processLocalProperty(tokens, pv); } } //實現屬性依賴注入功能 @SuppressWarnings("unchecked") private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) { //調用屬性的getter(readerMethod)方法,獲取屬性的值 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); //調用屬性的getter(readerMethod)方法,獲取屬性的值 propValue = getPropertyValue(tokens.actualName); } //將屬性的值賦值給數組中的元素 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集合的size int 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的長度大於屬性值的長度,則多餘的元素賦值爲null if (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中 list.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; TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType); //解析map類型屬性key值 Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor); Object oldValue = null; if (isExtractOldValueForEditor()) { oldValue = map.get(convertedMapKey); } //解析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 + "]"); } }
由此可知Spring IOC容器是這樣將屬性的值注入到Bean實例對象中的:
(1)對於集合類型的屬性,將其屬性值解析爲目標類型的集合後直接賦值給屬性;
(2)對於非集合類型的屬性,大量使用了JDK的反射和內省機制,經過屬性的getter方法(reader Method)獲取指定屬性注入之前的值,同時調用屬性的setter方法(writer Method)爲屬性設置注入後的值。 component
到這裏Spring IOC容器對Bean定義資源文件的定位、載入、解析和依賴注入已經所有分析完了,如今Spring IOC容器中管理了一系列靠依賴關係聯繫起來的Bean,程序不須要應用本身手動建立所需的對象,Spring IOC容器會在咱們使用的時候自動爲咱們建立,而且注入好相關的依賴,這就是Spring核心功能的控制反轉和依賴注入的相關功能。對象