Spring源码--IOC容器实现(6)--Bean依赖注入

前言

Github:https://github.com/yihonglei/thinking-in-spring

在前面文章中分析了容器初始化过程,建立一个可以使用的容器以及Bean对象的创建过程。

1)BeanDefinition的Resource定位

2)BeanDefinition的载入和解析

3)BeanDefinition的注册

4)Bean对象的创建

从上文“Bean对象的创建”中提到过,BeanFactory中getBean方法不仅是bean创建分析的入口,

也是依赖注入分析的入口,因为只有完成这两个步,才能返回给用户一个预期的Bean对象。

回顾一下上文中的AbstractAutowireCapableBeanFactory.doCreateBean()方法源码:


 
 
  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
  2. throws BeanCreationException {
  3. // Instantiate the bean.
  4. // 这个BeanWrapper是用来持有创建出来的Bean对象
  5. BeanWrapper instanceWrapper = null;
  6. // 如果是Singleton,先把缓存中的同名Bean清除
  7. if (mbd.isSingleton()) {
  8. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  9. }
  10. // 通过createBeanInstance()创建Bean
  11. if (instanceWrapper == null) {
  12. instanceWrapper = createBeanInstance(beanName, mbd, args);
  13. }
  14. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
  15. Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
  16. mbd.resolvedTargetType = beanType;
  17. // Allow post-processors to modify the merged bean definition.
  18. synchronized (mbd.postProcessingLock) {
  19. if (!mbd.postProcessed) {
  20. try {
  21. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  22. }
  23. catch (Throwable ex) {
  24. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  25. "Post-processing of merged bean definition failed", ex);
  26. }
  27. mbd.postProcessed = true;
  28. }
  29. }
  30. // Eagerly cache singletons to be able to resolve circular references
  31. // even when triggered by lifecycle interfaces like BeanFactoryAware.
  32. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  33. isSingletonCurrentlyInCreation(beanName));
  34. if (earlySingletonExposure) {
  35. if (logger.isDebugEnabled()) {
  36. logger.debug( "Eagerly caching bean '" + beanName +
  37. "' to allow for resolving potential circular references");
  38. }
  39. addSingletonFactory(beanName, new ObjectFactory<Object>() {
  40. @Override
  41. public Object getObject() throws BeansException {
  42. return getEarlyBeanReference(beanName, mbd, bean);
  43. }
  44. });
  45. }
  46. // Initialize the bean instance.
  47. // 对Bean进行初始化,这个exposedObject在初始化以后会返回座位依赖注入完成后的Bean
  48. Object exposedObject = bean;
  49. try {
  50. populateBean(beanName, mbd, instanceWrapper);
  51. if (exposedObject != null) {
  52. exposedObject = initializeBean(beanName, exposedObject, mbd);
  53. }
  54. }
  55. catch (Throwable ex) {
  56. if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
  57. throw (BeanCreationException) ex;
  58. }
  59. else {
  60. throw new BeanCreationException(
  61. mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
  62. }
  63. }
  64. if (earlySingletonExposure) {
  65. Object earlySingletonReference = getSingleton(beanName, false);
  66. if (earlySingletonReference != null) {
  67. if (exposedObject == bean) {
  68. exposedObject = earlySingletonReference;
  69. }
  70. else if (! this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
  71. String[] dependentBeans = getDependentBeans(beanName);
  72. Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
  73. for (String dependentBean : dependentBeans) {
  74. if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
  75. actualDependentBeans.add(dependentBean);
  76. }
  77. }
  78. if (!actualDependentBeans.isEmpty()) {
  79. throw new BeanCurrentlyInCreationException(beanName,
  80. "Bean with name '" + beanName + "' has been injected into other beans [" +
  81. StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
  82. "] in its raw version as part of a circular reference, but has eventually been " +
  83. "wrapped. This means that said other beans do not use the final version of the " +
  84. "bean. This is often the result of over-eager type matching - consider using " +
  85. "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
  86. }
  87. }
  88. }
  89. }
  90. // Register bean as disposable.
  91. try {
  92. registerDisposableBeanIfNecessary(beanName, bean, mbd);
  93. }
  94. catch (BeanDefinitionValidationException ex) {
  95. throw new BeanCreationException(
  96. mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
  97. }
  98. return exposedObject;
  99. }

这个doCreateBean()中有两个方法,在上文已经从createBeanInstance()方法分析了Bean的创建过程,

还有另外一个populateBean()方法,这个是依赖注入的分析入口。

AbstractAutowireCapableBeanFactory.populateBean()方法源码:


 
 
  1. protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
  2. // 获取BeanDefinition中设置的property值
  3. PropertyValues pvs = mbd.getPropertyValues();
  4. if (bw == null) {
  5. if (!pvs.isEmpty()) {
  6. throw new BeanCreationException(
  7. mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
  8. }
  9. else {
  10. // Skip property population phase for null instance.
  11. return;
  12. }
  13. }
  14. // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
  15. // state of the bean before properties are set. This can be used, for example,
  16. // to support styles of field injection.
  17. boolean continueWithPropertyPopulation = true;
  18. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  19. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  20. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  21. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  22. if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
  23. continueWithPropertyPopulation = false;
  24. break;
  25. }
  26. }
  27. }
  28. }
  29. if (!continueWithPropertyPopulation) {
  30. return;
  31. }
  32. // 开始进行依赖注入过程,先处理autowire的注入
  33. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
  34. mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  35. MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
  36. // Add property values based on autowire by name if applicable.
  37. // 根据Bean的名字,完成Bean的autowire
  38. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
  39. autowireByName(beanName, mbd, bw, newPvs);
  40. }
  41. // Add property values based on autowire by type if applicable.
  42. // 根据Bean的类型,完成Bean的autowire
  43. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  44. autowireByType(beanName, mbd, bw, newPvs);
  45. }
  46. pvs = newPvs;
  47. }
  48. boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
  49. boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
  50. if (hasInstAwareBpps || needsDepCheck) {
  51. PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
  52. if (hasInstAwareBpps) {
  53. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  54. if (bp instanceof InstantiationAwareBeanPostProcessor) {
  55. InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  56. pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
  57. if (pvs == null) {
  58. return;
  59. }
  60. }
  61. }
  62. }
  63. if (needsDepCheck) {
  64. checkDependencies(beanName, mbd, filteredPds, pvs);
  65. }
  66. }
  67. // 对属性进行注入
  68. applyPropertyValues(beanName, mbd, bw, pvs);
  69. }

 

看这块代码有几点我们要明确:

1)后面所讲的内容全部是bean在xml中的定义的内容,我们平时用的@Resource @Autowired并不是在这里解析的,

那些属于Spring注解的内容。

2)这里的autowire跟@Autowired不一样,autowire是Spring配置文件中的一个配置,@Autowired是一个注解。

<bean id="personFactory" class="com.xx.PersonFactory" autowire="byName">

一般Spring不建议autowire的配置。

下面分析applyPropertyValues()方法实现了属性注入的解析过程。

AbstractAutowireCapableBeanFactory.applyPropertyValues()方法源码:


 
 
  1. protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
  2. if (pvs == null || pvs.isEmpty()) {
  3. return;
  4. }
  5. MutablePropertyValues mpvs = null;
  6. List<PropertyValue> original;
  7. if (System.getSecurityManager() != null) {
  8. if (bw instanceof BeanWrapperImpl) {
  9. ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
  10. }
  11. }
  12. if (pvs instanceof MutablePropertyValues) {
  13. mpvs = (MutablePropertyValues) pvs;
  14. if (mpvs.isConverted()) {
  15. // Shortcut: use the pre-converted values as-is.
  16. try {
  17. bw.setPropertyValues(mpvs);
  18. return;
  19. }
  20. catch (BeansException ex) {
  21. throw new BeanCreationException(
  22. mbd.getResourceDescription(), beanName, "Error setting property values", ex);
  23. }
  24. }
  25. original = mpvs.getPropertyValueList();
  26. }
  27. else {
  28. original = Arrays.asList(pvs.getPropertyValues());
  29. }
  30. TypeConverter converter = getCustomTypeConverter();
  31. if (converter == null) {
  32. converter = bw;
  33. }
  34. // BeanDefinition在BeanDefinitionValueResolver中完成
  35. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver( this, beanName, mbd, converter);
  36. // Create a deep copy, resolving any references for values.
  37. // 为解析值创建一个副本,副本的数据将会被注入到Bean中
  38. List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
  39. boolean resolveNecessary = false;
  40. for (PropertyValue pv : original) {
  41. if (pv.isConverted()) {
  42. deepCopy.add(pv);
  43. }
  44. else {
  45. String propertyName = pv.getName();
  46. Object originalValue = pv.getValue();
  47. Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
  48. Object convertedValue = resolvedValue;
  49. boolean convertible = bw.isWritableProperty(propertyName) &&
  50. !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
  51. if (convertible) {
  52. convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
  53. }
  54. // Possibly store converted value in merged bean definition,
  55. // in order to avoid re-conversion for every created bean instance.
  56. if (resolvedValue == originalValue) {
  57. if (convertible) {
  58. pv.setConvertedValue(convertedValue);
  59. }
  60. deepCopy.add(pv);
  61. }
  62. else if (convertible && originalValue instanceof TypedStringValue &&
  63. !((TypedStringValue) originalValue).isDynamic() &&
  64. !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
  65. pv.setConvertedValue(convertedValue);
  66. deepCopy.add(pv);
  67. }
  68. else {
  69. resolveNecessary = true;
  70. deepCopy.add( new PropertyValue(pv, convertedValue));
  71. }
  72. }
  73. }
  74. if (mpvs != null && !resolveNecessary) {
  75. mpvs.setConverted();
  76. }
  77. // Set our (possibly massaged) deep copy.
  78. try {
  79. // 这里是依赖注入放生的地方,将副本依赖注入,具体实现在BeanWrapperImpl中完成
  80. bw.setPropertyValues( new MutablePropertyValues(deepCopy));
  81. }
  82. catch (BeansException ex) {
  83. throw new BeanCreationException(
  84. mbd.getResourceDescription(), beanName, "Error setting property values", ex);
  85. }
  86. }

通过使用BeanDefinitionValueResolver来对BeanDefinition进行解析,然后注入到property中。

下面分析下BeanDefinitionValueResolver中如何解析,以对Bean Reference进行解析为例。

BeanDefinitionValueResolver.resolveValueIfNecessary()方法源码:


 
 
  1. public Object resolveValueIfNecessary(Object argName, Object value) {
  2. // We must check each value to see whether it requires a runtime reference
  3. // to another bean to be resolved.
  4. // 检查每个值,看看它是否需要一个运行时引用来解析另一个bean
  5. if (value instanceof RuntimeBeanReference) {
  6. RuntimeBeanReference ref = (RuntimeBeanReference) value;
  7. return resolveReference(argName, ref);
  8. }
  9. else if (value instanceof RuntimeBeanNameReference) {
  10. String refName = ((RuntimeBeanNameReference) value).getBeanName();
  11. refName = String.valueOf(doEvaluate(refName));
  12. if (! this.beanFactory.containsBean(refName)) {
  13. throw new BeanDefinitionStoreException(
  14. "Invalid bean name '" + refName + "' in bean reference for " + argName);
  15. }
  16. return refName;
  17. }
  18. else if (value instanceof BeanDefinitionHolder) {
  19. // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
  20. BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
  21. return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
  22. }
  23. else if (value instanceof BeanDefinition) {
  24. // Resolve plain BeanDefinition, without contained name: use dummy name.
  25. BeanDefinition bd = (BeanDefinition) value;
  26. String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
  27. ObjectUtils.getIdentityHexString(bd);
  28. return resolveInnerBean(argName, innerBeanName, bd);
  29. }
  30. // 对ManagedArray进行解析
  31. else if (value instanceof ManagedArray) {
  32. // May need to resolve contained runtime references.
  33. ManagedArray array = (ManagedArray) value;
  34. Class<?> elementType = array.resolvedElementType;
  35. if (elementType == null) {
  36. String elementTypeName = array.getElementTypeName();
  37. if (StringUtils.hasText(elementTypeName)) {
  38. try {
  39. elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
  40. array.resolvedElementType = elementType;
  41. }
  42. catch (Throwable ex) {
  43. // Improve the message by showing the context.
  44. throw new BeanCreationException(
  45. this.beanDefinition.getResourceDescription(), this.beanName,
  46. "Error resolving array type for " + argName, ex);
  47. }
  48. }
  49. else {
  50. elementType = Object.class;
  51. }
  52. }
  53. return resolveManagedArray(argName, (List<?>) value, elementType);
  54. }
  55. // 对ManagedList进行解析
  56. else if (value instanceof ManagedList) {
  57. // May need to resolve contained runtime references.
  58. return resolveManagedList(argName, (List<?>) value);
  59. }
  60. // 对ManagedSet进行解析
  61. else if (value instanceof ManagedSet) {
  62. // May need to resolve contained runtime references.
  63. return resolveManagedSet(argName, (Set<?>) value);
  64. }
  65. // 对ManagedMap进行解析
  66. else if (value instanceof ManagedMap) {
  67. // May need to resolve contained runtime references.
  68. return resolveManagedMap(argName, (Map<?, ?>) value);
  69. }
  70. // 对ManagedProperties进行解析
  71. else if (value instanceof ManagedProperties) {
  72. Properties original = (Properties) value;
  73. Properties copy = new Properties();
  74. for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
  75. Object propKey = propEntry.getKey();
  76. Object propValue = propEntry.getValue();
  77. if (propKey instanceof TypedStringValue) {
  78. propKey = evaluate((TypedStringValue) propKey);
  79. }
  80. if (propValue instanceof TypedStringValue) {
  81. propValue = evaluate((TypedStringValue) propValue);
  82. }
  83. copy.put(propKey, propValue);
  84. }
  85. return copy;
  86. }
  87. // 对TypedStringValue进行解析
  88. else if (value instanceof TypedStringValue) {
  89. // Convert value to target type here.
  90. TypedStringValue typedStringValue = (TypedStringValue) value;
  91. Object valueObject = evaluate(typedStringValue);
  92. try {
  93. Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
  94. if (resolvedTargetType != null) {
  95. return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
  96. }
  97. else {
  98. return valueObject;
  99. }
  100. }
  101. catch (Throwable ex) {
  102. // Improve the message by showing the context.
  103. throw new BeanCreationException(
  104. this.beanDefinition.getResourceDescription(), this.beanName,
  105. "Error converting typed String value for " + argName, ex);
  106. }
  107. }
  108. else {
  109. return evaluate(value);
  110. }
  111. }

第一个if条件中的代码,表示对于RuntimeBeanReference类型的注入在resolveReference中。

BeanDefinitionValueResolver.resolveReference()方法源码:


 
 
  1. private Object resolveReference(Object argName, RuntimeBeanReference ref) {
  2. try {
  3. // 从reference名字,这个refName实在载入BeanDefinition时根据配置生成的
  4. String refName = ref.getBeanName();
  5. refName = String.valueOf(doEvaluate(refName));
  6. // 如果ref是在双亲IOC容器中,那就到双亲IOC容器中获取
  7. if (ref.isToParent()) {
  8. if ( this.beanFactory.getParentBeanFactory() == null) {
  9. throw new BeanCreationException(
  10. this.beanDefinition.getResourceDescription(), this.beanName,
  11. "Can't resolve reference to bean '" + refName +
  12. "' in parent factory: no parent factory available");
  13. }
  14. return this.beanFactory.getParentBeanFactory().getBean(refName);
  15. }
  16. // 在当前IOC容器中获取Bean,这里会触发一个getBean的过程,如果依赖注入没有发生,
  17. // 这里会触发相应的依赖注入的发生
  18. else {
  19. Object bean = this.beanFactory.getBean(refName);
  20. this.beanFactory.registerDependentBean(refName, this.beanName);
  21. return bean;
  22. }
  23. }
  24. catch (BeansException ex) {
  25. throw new BeanCreationException(
  26. this.beanDefinition.getResourceDescription(), this.beanName,
  27. "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
  28. }
  29. }

BeanDefinitionValueResolver.resolveManagedList()方法源码:

对managedList的处理过程。


 
 
  1. private List<?> resolveManagedList(Object argName, List<?> ml) {
  2. List<Object> resolved = new ArrayList<Object>(ml.size());
  3. for ( int i = 0; i < ml.size(); i++) {
  4. // 通过递归的方式,对List的元素进行解析
  5. resolved.add(
  6. resolveValueIfNecessary( new KeyedArgName(argName, i), ml.get(i)));
  7. }
  8. return resolved;
  9. }

完成这个解析过程后,也即是BeanDefinitionValueResolver的resolveValueIfNecessary()方法中的相关内容执行完成后,

这个时候未依赖注入准备好了条件,这是真正把Bean对象设置到所有依赖的因一个Bean属性中的地方,其中处理的属性

是各种各样的。

依赖注入的发生在BeanWrapperImpl中实现的。

bean属性注入通过setPropertyValues()方法完成,这是PropertyAccessor接口方法,

实现类是AbstractPropertyAccessor,看一下调用的源码。

AbstractPropertyAccessor.setPropertyValues()方法源码:

调用入口


 
 
  1. @Override
  2. public void setPropertyValues(PropertyValues pvs) throws BeansException {
  3. setPropertyValues(pvs, false, false);
  4. }

 
 
  1. @Override
  2. public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
  3. throws BeansException {
  4. List<PropertyAccessException> propertyAccessExceptions = null;
  5. // 得到属性列表
  6. List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
  7. ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
  8. for (PropertyValue pv : propertyValues) {
  9. try {
  10. // This method may throw any BeansException, which won't be caught
  11. // here, if there is a critical failure such as no matching field.
  12. // We can attempt to deal only with less serious exceptions.
  13. // 属性注入
  14. setPropertyValue(pv);
  15. }
  16. catch (NotWritablePropertyException ex) {
  17. if (!ignoreUnknown) {
  18. throw ex;
  19. }
  20. // Otherwise, just ignore it and continue...
  21. }
  22. catch (NullValueInNestedPathException ex) {
  23. if (!ignoreInvalid) {
  24. throw ex;
  25. }
  26. // Otherwise, just ignore it and continue...
  27. }
  28. catch (PropertyAccessException ex) {
  29. if (propertyAccessExceptions == null) {
  30. propertyAccessExceptions = new LinkedList<PropertyAccessException>();
  31. }
  32. propertyAccessExceptions.add(ex);
  33. }
  34. }
  35. // If we encountered individual exceptions, throw the composite exception.
  36. if (propertyAccessExceptions != null) {
  37. PropertyAccessException[] paeArray =
  38. propertyAccessExceptions.toArray( new PropertyAccessException[propertyAccessExceptions.size()]);
  39. throw new PropertyBatchUpdateException(paeArray);
  40. }
  41. }

代码追溯到:


 
 
  1. protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
  2. if (tokens.keys != null) {
  3. processKeyedProperty(tokens, pv);
  4. }
  5. else {
  6. processLocalProperty(tokens, pv);
  7. }
  8. }

最后到在processKeyedProperty中完成依赖注入的处理:


 
 
  1. private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
  2. Object propValue = getPropertyHoldingValue(tokens);
  3. String lastKey = tokens.keys[tokens.keys.length - 1];
  4. if (propValue.getClass().isArray()) {
  5. PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
  6. Class<?> requiredType = propValue.getClass().getComponentType();
  7. int arrayIndex = Integer.parseInt(lastKey);
  8. Object oldValue = null;
  9. try {
  10. if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
  11. oldValue = Array.get(propValue, arrayIndex);
  12. }
  13. Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
  14. requiredType, ph.nested(tokens.keys.length));
  15. int length = Array.getLength(propValue);
  16. if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
  17. Class<?> componentType = propValue.getClass().getComponentType();
  18. Object newArray = Array.newInstance(componentType, arrayIndex + 1);
  19. System.arraycopy(propValue, 0, newArray, 0, length);
  20. setPropertyValue(tokens.actualName, newArray);
  21. propValue = getPropertyValue(tokens.actualName);
  22. }
  23. Array.set(propValue, arrayIndex, convertedValue);
  24. }
  25. catch (IndexOutOfBoundsException ex) {
  26. throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
  27. "Invalid array index in property path '" + tokens.canonicalName + "'", ex);
  28. }
  29. }
  30. else if (propValue instanceof List) {
  31. PropertyHandler ph = getPropertyHandler(tokens.actualName);
  32. Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
  33. List<Object> list = (List<Object>) propValue;
  34. int index = Integer.parseInt(lastKey);
  35. Object oldValue = null;
  36. if (isExtractOldValueForEditor() && index < list.size()) {
  37. oldValue = list.get(index);
  38. }
  39. Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
  40. requiredType, ph.nested(tokens.keys.length));
  41. int size = list.size();
  42. if (index >= size && index < this.autoGrowCollectionLimit) {
  43. for ( int i = size; i < index; i++) {
  44. try {
  45. list.add( null);
  46. }
  47. catch (NullPointerException ex) {
  48. throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
  49. "Cannot set element with index " + index + " in List of size " +
  50. size + ", accessed using property path '" + tokens.canonicalName +
  51. "': List does not support filling up gaps with null elements");
  52. }
  53. }
  54. list.add(convertedValue);
  55. }
  56. else {
  57. try {
  58. list.set(index, convertedValue);
  59. }
  60. catch (IndexOutOfBoundsException ex) {
  61. throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
  62. "Invalid list index in property path '" + tokens.canonicalName + "'", ex);
  63. }
  64. }
  65. }
  66. else if (propValue instanceof Map) {
  67. PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
  68. Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
  69. Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
  70. Map<Object, Object> map = (Map<Object, Object>) propValue;
  71. // IMPORTANT: Do not pass full property name in here - property editors
  72. // must not kick in for map keys but rather only for map values.
  73. TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
  74. Object convertedMapKey = convertIfNecessary( null, null, lastKey, mapKeyType, typeDescriptor);
  75. Object oldValue = null;
  76. if (isExtractOldValueForEditor()) {
  77. oldValue = map.get(convertedMapKey);
  78. }
  79. // Pass full property name and old value in here, since we want full
  80. // conversion ability for map values.
  81. Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
  82. mapValueType, ph.nested(tokens.keys.length));
  83. map.put(convertedMapKey, convertedMapValue);
  84. }
  85. else {
  86. throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
  87. "Property referenced in indexed property path '" + tokens.canonicalName +
  88. "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
  89. }
  90. }

这个地方spring 3和Spring 4差别非常大,这里是基于spring 4的源码。

 

参考文献:

1、《Spring技术内幕》

2、《Spring实战》

3、Spring官网API

4、Spring源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值