解析属性注入规则
當容器在對屬性進行依賴注入時,如果發現屬性值需要進行類型轉換,如屬性值是容器中另一個Bean實例對象的引用,則容器首先需要根據屬性值解析出所引用的對象,然后才能將該引用對象注入到目標實例對象的屬性上去,對屬性進行解析的由resolveValueIfNecessary()方法實現,其源碼如下:
//解析屬性值,對注入類型進行轉換 @Nullable public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {// We must check each value to see whether it requires a runtime reference// to another bean to be resolved.//對引用類型的屬性進行解析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));//從容器中獲取指定名稱的Beanif (!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) {// Resolve plain BeanDefinition, without contained name: use dummy name.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) {// May need to resolve contained runtime references.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) {// Improve the message by showing the context.throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Error resolving array type for " + argName, ex);}}//沒有獲取到數組的類型,也沒有獲取到數組元素的類型//則直接設置數組的類型為Objectelse {elementType = Object.class;}}//創建指定類型的數組return resolveManagedArray(argName, (List<?>) value, elementType);}//解析list類型的屬性值else if (value instanceof ManagedList) {// May need to resolve contained runtime references.return resolveManagedList(argName, (List<?>) value);}//解析set類型的屬性值else if (value instanceof ManagedSet) {// May need to resolve contained runtime references.return resolveManagedSet(argName, (Set<?>) value);}//解析map類型的屬性值else if (value instanceof ManagedMap) {// May need to resolve contained runtime references.return resolveManagedMap(argName, (Map<?, ?>) value);}//解析props類型的屬性值,props其實就是key和value均為字符串的mapelse 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) {// Convert value to target type here.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) {// Improve the message by showing the context.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);} } //解析array類型的屬性 private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {//創建一個指定類型的數組,用于存放和返回解析后的數組Object resolved = Array.newInstance(elementType, ml.size());for (int i = 0; i < ml.size(); i++) {//遞歸解析array的每一個元素,并將解析后的值設置到resolved數組中,索引為iArray.set(resolved, i,resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));}return resolved; }通過上面的代碼分析,我們明白了Spring 是如何將引用類型,內部類以及集合類型等屬性進行解析的,屬性值解析完成后就可以進行依賴注入了,依賴注入的過程就是Bean 對象實例設置到它所依賴的Bean對象屬性上去。而真正的依賴注入是通過bw.setPropertyValues()方法實現的,該方法也使用了委托模式, 在BeanWrapper 接口中至少定義了方法聲明, 依賴注入的具體實現交由其實現類BeanWrapperImpl 來完成,下面我們就分析依BeanWrapperImpl 中賴注入相關的源碼。
?
總結