SpringIoC依赖注入的过程(五)
2015-11-07 22:46
399 查看
SpringIoC依赖注入的过程(五)
前面的文章讲到,Spring通过populateBean方法实现依赖的注入。它先是解析需要自动注入的属性,并且把解析出来的属性值保存到PropertyValues中,没有把解析出来的属性值直接设置到bean中;然后就对Autowired、Resource的属性和方法进行注入,直接设置了bean的属性值。现在依赖注入还差两个任务,一个是把之前解析出来的属性值设置到bean中去;一个是继续解析出BeanDefinition中定义好的属性值。这两个任务都包含在populateBean的applyPropertyValues方法中protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs == null || pvs.isEmpty()) { return; } MutablePropertyValues mpvs = null; List<PropertyValue> original; if (System.getSecurityManager()!= null) { if (bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } } if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; if (mpvs.isConverted()) { // 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 valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); // Create a deep copy, resolving any references for values. List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(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; 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); } }这个方法大概是这个样子的,首先创建一个列表deepCopy用于保存所有PropertyValue解析之后的值。接下来分别处理每一个PropertyValue,每个PropertyValue经历两个处理过程。第一个处理过程是解析,这里并不是说重新解析,只是对于之前没有解析过得属性(比如,在BeanDefinition中直接定义的属性值以及引用)进行解析;第二个处理过程是转换,把获取到的依赖bean的类型转换成属性的类型,如果不匹配会抛出异常。然后将解析并转换后的值加入到deepCopy中。最后再分别设置到属性中去。
对PropertyValue的解析发生在BeanDefinitionValueResolver的resolveValueIfNecessary方法中
public Object resolveValueIfNecessary(Object argName, 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); } else if (value instanceof RuntimeBeanNameReference) { String refName = ((RuntimeBeanNameReference) value).getBeanName(); refName = String.valueOf(evaluate(refName)); if (!this.beanFactory.containsBean(refName)) { throw new BeanDefinitionStoreException( "Invalid bean name '" + refName + "' in bean reference for " + argName); } return refName; } 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; return resolveInnerBean(argName, "(inner bean)", 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); } } else { elementType = Object.class; } } return resolveManagedArray(argName, (List<?>) value, elementType); } else if (value instanceof ManagedList) { // May need to resolve contained runtime references. return resolveManagedList(argName, (List<?>) value); } else if (value instanceof ManagedSet) { // May need to resolve contained runtime references. return resolveManagedSet(argName, (Set<?>) value); } else if (value instanceof ManagedMap) { // May need to resolve contained runtime references. return resolveManagedMap(argName, (Map<?, ?>) value); } else if (value instanceof ManagedProperties) { Properties original = (Properties) value; Properties copy = new Properties(); for (Map.Entry propEntry : original.entrySet()) { Object propKey = propEntry.getKey(); Object propValue = propEntry.getValue(); if (propKey instanceof TypedStringValue) { propKey = evaluate((TypedStringValue) propKey); } if (propValue instanceof TypedStringValue) { propValue = evaluate((TypedStringValue) propValue); } 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); } 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 { return evaluate(value); } }
又是一个比较长的方法,可以看到,针对每一种属性值都要不同的解析方法。在这一块,需要解析的类型最常见的就是对于其他bean的引用,也就是上面的RuntimeBeanReference,那么看看resolveReference都做了什么
private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { String refName = ref.getBeanName(); refName = String.valueOf(evaluate(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"); } return this.beanFactory.getParentBeanFactory().getBean(refName); } else { Object bean = this.beanFactory.getBean(refName); this.beanFactory.registerDependentBean(refName, this.beanName); return bean; } } catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); } }好像一切都在意料之中,没错,这里就是利用引用的bean的名字向容器索要这个bean,即递归调用getBean。其他几种类型也都类似,就不一一列举了。如果属性的值以及在之前解析出来了,也就是在resolveValueIfNecessary方法中的value以及是依赖的bean的类型的对象了,那么什么也不做直接返回就好了。关于类型转换的过程,跟依赖注入的关系不大,这里就不详细解释了。在applyPropertyValues中已经列出,设置bean的属性值是通过BeanWrapper的setPropertyValues方法达到的。而BeanWrapper设置属性值得办法就是通过反射调用set方法,具体过程还涉及到很多其他的细节,也不在依赖注入里细说了。
截止目前,populateBean方法的逻辑就全部解释完毕了,Spring中真正依赖注入的过程也结束了。下一篇做个收尾,说一下populateBean之后的工作。
相关文章推荐
- gradle eclipse web模板项目构建
- Java String之intern()方法深入分析
- java静态代码块、初始化块和构造方法的执行顺序
- java 泛型详解
- 剖析怎样使用Spring的PropertyPlaceholderConfigurer占位符
- java 反射学习
- 简单的网页验证码设计——学习笔记
- 用Java SPI实现可插拔
- Java停止一个线程的几种方法
- java输入
- MAC $JAVA_HOME设置
- 百度echarts后台Java封装小实例
- JAVA使用DES加密算法加密解密
- android 在eclipse中把局部变量变成成员变量前自动加m
- Springmvc返回json
- 基数排序
- Java web 中实现简单的文件上传与下载——学习笔记
- eclipse web helloworld
- 剖析Java同步块synchronized及常用使用方法
- Java实现二叉树、 双链表