Java面试Spring源码分析 —— Spring IoC
Posted 醉恋学Java
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java面试Spring源码分析 —— Spring IoC相关的知识,希望对你有一定的参考价值。
7、BeanDefinitionValueResolver解析属性值:
当容器在对属性进行依赖注入时,如果发现属性值需要进行类型转换,如属性值是容器中另一个Bean实例对象的引用,则容器首先需要根据属性值解析出所引用的对象,然后才能将该引用对象注入到目标实例对象的属性上去,对属性进行解析的由resolveValueIfNecessary方法实现,其源码如下:
1 //解析属性值,对注入类型进行转换 2 public Object resolveValueIfNecessary(Object argName, Object value) { 3 //对引用类型的属性进行解析 4 if (value instanceof RuntimeBeanReference) { 5 RuntimeBeanReference ref = (RuntimeBeanReference) value; 6 //调用引用类型属性的解析方法 7 return resolveReference(argName, ref); 8 } 9 //对属性值是引用容器中另一个Bean名称的解析 10 else if (value instanceof RuntimeBeanNameReference) { 11 String refName = ((RuntimeBeanNameReference) value).getBeanName(); 12 refName = String.valueOf(evaluate(refName)); 13 //从容器中获取指定名称的Bean 14 if (!this.beanFactory.containsBean(refName)) { 15 throw new BeanDefinitionStoreException( 16 "Invalid bean name '" + refName + "' in bean reference for " + argName); 17 } 18 return refName; 19 } 20 //对Bean类型属性的解析,主要是Bean中的内部类 21 else if (value instanceof BeanDefinitionHolder) { 22 BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; 23 return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); 24 } 25 else if (value instanceof BeanDefinition) { 26 BeanDefinition bd = (BeanDefinition) value; 27 return resolveInnerBean(argName, "(inner bean)", bd); 28 } 29 //对集合数组类型的属性解析 30 else if (value instanceof ManagedArray) { 31 ManagedArray array = (ManagedArray) value; 32 //获取数组的类型 33 Class elementType = array.resolvedElementType; 34 if (elementType == null) { 35 //获取数组元素的类型 36 String elementTypeName = array.getElementTypeName(); 37 if (StringUtils.hasText(elementTypeName)) { 38 try { 39 //使用反射机制创建指定类型的对象 40 elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); 41 array.resolvedElementType = elementType; 42 } 43 catch (Throwable ex) { 44 throw new BeanCreationException( 45 this.beanDefinition.getResourceDescription(), this.beanName, 46 "Error resolving array type for " + argName, ex); 47 } 48 } 49 //没有获取到数组的类型,也没有获取到数组元素的类型,则直接设置数 50 //组的类型为Object 51 else { 52 elementType = Object.class; 53 } 54 } 55 //创建指定类型的数组 56 return resolveManagedArray(argName, (List<?>) value, elementType); 57 } 58 //解析list类型的属性值 59 else if (value instanceof ManagedList) { 60 return resolveManagedList(argName, (List<?>) value); 61 } 62 //解析set类型的属性值 63 else if (value instanceof ManagedSet) { 64 return resolveManagedSet(argName, (Set<?>) value); 65 } 66 //解析map类型的属性值 67 else if (value instanceof ManagedMap) { 68 return resolveManagedMap(argName, (Map<?, ?>) value); 69 } 70 //解析props类型的属性值,props其实就是key和value均为字符串的map 71 else if (value instanceof ManagedProperties) { 72 Properties original = (Properties) value; 73 //创建一个拷贝,用于作为解析后的返回值 74 Properties copy = new Properties(); 75 for (Map.Entry propEntry : original.entrySet()) { 76 Object propKey = propEntry.getKey(); 77 Object propValue = propEntry.getValue(); 78 if (propKey instanceof TypedStringValue) { 79 propKey = evaluate((TypedStringValue) propKey); 80 } 81 if (propValue instanceof TypedStringValue) { 82 propValue = evaluate((TypedStringValue) propValue); 83 } 84 copy.put(propKey, propValue); 85 } 86 return copy; 87 } 88 //解析字符串类型的属性值 89 else if (value instanceof TypedStringValue) { 90 TypedStringValue typedStringValue = (TypedStringValue) value; 91 Object valueObject = evaluate(typedStringValue); 92 try { 93 //获取属性的目标类型 94 Class<?> resolvedTargetType = resolveTargetType(typedStringValue); 95 if (resolvedTargetType != null) { 96 //对目标类型的属性进行解析,递归调用 97 return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); 98 } 99 //没有获取到属性的目标对象,则按Object类型返回 100 else { 101 return valueObject; 102 } 103 } 104 catch (Throwable ex) { 105 throw new BeanCreationException( 106 this.beanDefinition.getResourceDescription(), this.beanName, 107 "Error converting typed String value for " + argName, ex); 108 } 109 } 110 else { 111 return evaluate(value); 112 } 113 } 114 //解析引用类型的属性值 115 private Object resolveReference(Object argName, RuntimeBeanReference ref) { 116 try { 117 //获取引用的Bean名称 118 String refName = ref.getBeanName(); 119 refName = String.valueOf(evaluate(refName)); 120 //如果引用的对象在父类容器中,则从父类容器中获取指定的引用对象 121 if (ref.isToParent()) { 122 if (this.beanFactory.getParentBeanFactory() == null) { 123 throw new BeanCreationException( 124 this.beanDefinition.getResourceDescription(), this.beanName, 125 "Can't resolve reference to bean '" + refName + 126 "' in parent factory: no parent factory available"); 127 } 128 return this.beanFactory.getParentBeanFactory().getBean(refName); 129 } 130 //从当前的容器中获取指定的引用Bean对象,如果指定的Bean没有被实例化 131 //则会递归触发引用Bean的初始化和依赖注入 132 else { 133 Object bean = this.beanFactory.getBean(refName); 134 //将当前实例化对象的依赖引用对象 135 this.beanFactory.registerDependentBean(refName, this.beanName); 136 return bean; 137 } 138 } 139 catch (BeansException ex) { 140 throw new BeanCreationException( 141 this.beanDefinition.getResourceDescription(), this.beanName, 142 "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); 143 } 144 } 145 //解析array类型的属性 146 private Object resolveManagedArray(Object argName, List<?> ml, Class elementType) { 147 //创建一个指定类型的数组,用于存放和返回解析后的数组 148 Object resolved = Array.newInstance(elementType, ml.size()); 149 for (int i = 0; i < ml.size(); i++) { 150 //递归解析array的每一个元素,并将解析后的值设置到resolved数组中,索引为i 151 Array.set(resolved, i, 152 resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); 153 } 154 return resolved; 155 } 156 //解析list类型的属性 157 private List resolveManagedList(Object argName, List<?> ml) { 158 List<Object> resolved = new ArrayList<Object>(ml.size()); 159 for (int i = 0; i < ml.size(); i++) { 160 //递归解析list的每一个元素 161 resolved.add( 162 resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); 163 } 164 return resolved; 165 } 166 //解析set类型的属性 167 private Set resolveManagedSet(Object argName, Set<?> ms) { 168 Set<Object> resolved = new LinkedHashSet<Object>(ms.size()); 169 int i = 0; 170 //递归解析set的每一个元素 171 for (Object m : ms) { 172 resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m)); 173 i++; 174 } 175 return resolved; 176 } 177 //解析map类型的属性 178 private Map resolveManagedMap(Object argName, Map<?, ?> mm) { 179 Map<Object, Object> resolved = new LinkedHashMap<Object, Object>(mm.size()); 180 //递归解析map中每一个元素的key和value 181 for (Map.Entry entry : mm.entrySet()) { 182 Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey()); 183 Object resolvedValue = resolveValueIfNecessary( 184 new KeyedArgName(argName, entry.getKey()), entry.getValue()); 185 resolved.put(resolvedKey, resolvedValue); 186 } 187 return resolved; 188 }
通过上面的代码分析,我们明白了Spring是如何将引用类型,内部类以及集合类型等属性进行解析的,属性值解析完成后就可以进行依赖注入了,依赖注入的过程就是Bean对象实例设置到它所依赖的Bean对象属性上去,在第7步中我们已经说过,依赖注入是通过bw.setPropertyValues方法实现的,该方法也使用了委托模式,在BeanWrapper接口中至少定义了方法声明,依赖注入的具体实现交由其实现类BeanWrapperImpl来完成,下面我们就分析依BeanWrapperImpl中赖注入相关的源码。
8、BeanWrapperImpl对Bean属性的依赖注入:
BeanWrapperImpl类主要是对容器中完成初始化的Bean实例对象进行属性的依赖注入,即把Bean对象设置到它所依赖的另一个Bean的属性中去,依赖注入的相关源码如下:
1 //实现属性依赖注入功能 2 private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { 3 //PropertyTokenHolder主要保存属性的名称、路径,以及集合的size等信息 4 String propertyName = tokens.canonicalName; 5 String actualName = tokens.actualName; 6 //keys是用来保存集合类型属性的size 7 if (tokens.keys != null) { 8 //将属性信息拷贝 9 PropertyTokenHolder getterTokens = new PropertyTokenHolder(); 10 getterTokens.canonicalName = tokens.canonicalName; 11 getterTokens.actualName = tokens.actualName; 12 getterTokens.keys = new String[tokens.keys.length - 1]; 13 System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); 14 Object propValue; 15 try { 16 //获取属性值,该方法内部使用JDK的内省( Introspector)机制,调用属性//的getter(readerMethod)方法,获取属性的值 17 propValue = getPropertyValue(getterTokens); 18 } 19 catch (NotReadablePropertyException ex) { 20 throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, 21 "Cannot access indexed value in property referenced " + 22 "in indexed property path '" + propertyName + "'", ex); 23 } 24 //获取集合类型属性的长度 25 String key = tokens.keys[tokens.keys.length - 1]; 26 if (propValue == null) { 27 throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, 28 "Cannot access indexed value in property referenced " + 29 "in indexed property path '" + propertyName + "': returned null"); 30 } 31 //注入array类型的属性值 32 else if (propValue.getClass().isArray()) { 33 //获取属性的描述符 34 PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); 35 //获取数组的类型 36 Class requiredType = propValue.getClass().getComponentType(); 37 //获取数组的长度 38 int arrayIndex = Integer.parseInt(key); 39 Object oldValue = null; 40 try { 41 //获取数组以前初始化的值 42 if (isExtractOldValueForEditor()) { 43 oldValue = Array.get(propValue, arrayIndex); 44 } 45 //将属性的值赋值给数组中的元素 46 Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, 47 new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType)); 48 Array.set(propValue, arrayIndex, convertedValue); 49 } 50 catch (IndexOutOfBoundsException ex) { 51 throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, 52 "Invalid array index in property path '" + propertyName + "'", ex); 53 } 54 } 55 //注入list类型的属性值 56 else if (propValue instanceof List) { 57 PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); 58 //获取list集合的类型 59 Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType( 60 pd.getReadMethod(), tokens.keys.length); 61 List list = (List) propValue; 62 //获取list集合的size 63 int index = Integer.parseInt(key); 64 Object oldValue = null; 65 if (isExtractOldValueForEditor() && index < list.size()) { 66 oldValue = list.get(index); 67 } 68 //获取list解析后的属性值 69 Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, 70 new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType)); 71 if (index < list.size()) { 72 //为list属性赋值 73 list.set(index, convertedValue); 74 } 75 //如果list的长度大于属性值的长度,则多余的元素赋值为null 76 else if (index >= list.size()) { 77 for (int i = list.size(); i < index; i++) { 78 try { 79 list.add(null); 80 } 81 catch (NullPointerException ex) { 82 throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, 83 "Cannot set element with index " + index + " in List of size " + 84 list.size() + ", accessed using property path '" + propertyName + 85 "': List does not support filling up gaps with null elements"); 86 } 87 } 88 list.add(convertedValue); 89 } 90 } 91 //注入map类型的属性值 92 else if (propValue instanceof Map) { 93 PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); 94 //获取map集合key的类型 95 Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType( 96 pd.getReadMethod(), tokens.keys.length); 97 //获取map集合value的类型 98 Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType( 99 pd.getReadMethod(), tokens.keys.length); 100 Map map = (Map) propValue; 101 //解析map类型属性key值 102 Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, 103 new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType)); 104 Object oldValue = null; 105 if (isExtractOldValueForEditor()) { 106 oldValue = map.get(convertedMapKey); 107 } 108 //解析map类型属性value值 109 Object convertedMapValue = convertIfNecessary( 110 propertyName, oldValue, pv.getValue(), mapValueType, 111 new TypeDescriptor(new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length + 1))); 112 //将解析后的key和value值赋值给map集合属性 113 map.put(convertedMapKey, convertedMapValue); 114 } 115 else { 116 throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, 117 "Property referenced in indexed property path '" + propertyName + 118 "' is neither an array nor a List nor a Map; returned value was [" + pv.getValue() + "]"); 119 } 120 } 121 //对非集合类型的属性注入 122 else { 123 PropertyDescriptor pd = pv.resolvedDescriptor; 124 if (pd == null || !pd.getWriteMethod().getDeclaringClass().isInstance(this.object)) { 125 pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); 126 //无法获取到属性名或者属性没有提供setter(写方法)方法 127 if (pd == null || pd.getWriteMethod() == null) { 128 //如果属性值是可选的,即不是必须的,则忽略该属性值 129 if (pv.isOptional()) { 130 logger.debug("Ignoring optional value for property '" + actualName + 131 "' - property not found on bean class [" + getRootClass().getName() + "]"); 132 return; 133 } 134 //如果属性值是必须的,则抛出无法给属性赋值,因为每天提供setter方法异常 135 else { 136 PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass()); 137 throw new NotWritablePropertyException( 138 getRootClass(), this.nestedPath + propertyName, 139 matches.buildErrorMessage(), matches.getPossibleMatches()); 140 } 141 } 142 pv.getOriginalPropertyValue().resolvedDescriptor = pd; 143 } 144 Object oldValue = null; 145 try { 146 Object originalValue = pv.getValue(); 147 Object valueToApply = originalValue; 148 if (!Boolean.FALSE.equals(pv.conversionNecessary)) { 149 if (pv.isConverted()) { 150 valueToApply = pv.getConvertedValue(); 151 } 152 else { 153 if (isExtractOldValueForEditor() && pd.getReadMethod() != null) { 154 //获取属性的getter方法(读方法),JDK内省机制 155 final Method readMethod = pd.getReadMethod(); 156 //如果属性的getter方法不是public访问控制权限的,即访问控制权限比较严格, 157 //则使用JDK的反射机制强行访问非public的方法(暴力读取属性值) 158 if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && 159 !readMethod.isAccessible()) { 160 if (System.getSecurityManager()!= null) { 161 //匿名内部类,根据权限修改属性的读取控制限制 162 AccessController.doPrivileged(new PrivilegedAction<Object>() { 163 public Object run() { 164 readMethod.setAccessible(true); 165 return null; 166 } 167 }); 168 } 169 else { 170 readMethod.setAccessible(true); 171 } 172 } 173 try { 174 //属性没有提供getter方法时,调用潜在的读取属性值//的方法,获取属性值 175 if (System.getSecurityManager() != null) { 176 oldValue = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 177 public Object run() throws Exception { 178 return readMethod.invoke(object); 179 } 180 }, acc); 181 } 182 else { 183 oldValue = readMethod.invoke(object); 184 } 185 } 186 catch (Exception ex) { 187 if (ex instanceof PrivilegedActionException) { 188 ex = ((PrivilegedActionException) ex).getException(); 189 } 190 if (logger.isDebugEnabled()) { 191 logger.debug("Could not read previous value of property '" + 192 this.nestedPath + propertyName + "'", ex); 193 } 194 } 195 } 196 //设置属性的注入值 197 valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd); 198 } 199 pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); 200 } 201 //根据JDK的内省机制,获取属性的setter(写方法)方法 202 final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ? 203 ((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() : 204 pd.getWriteMethod()); 205 //如果属性的setter方法是非public,即访问控制权限比较严格,则使用JDK的反射机制, 206 //强行设置setter方法可访问(暴力为属性赋值) 207 if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) { 208 //如果使用了JDK的安全机制,则需要权限验证 209 if (System.getSecurityManager()!= null) { 210 AccessController.doPrivileged(new PrivilegedAction<Object>() { 211 public Object run() { 212 writeMethod.setAccessible(true); 213 return null; 214 } 215 }); 216 } 217 else { 218 writeMethod.setAccessible(true); 219 } 220 } 221 final Object value = valueToApply; 222 if (System.getSecurityManager() != null) { 223 try { 224 //将属性值设置到属性上去 225 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 226 public Object run() throws Exception { 227 writeMethod.invoke(object, value); 228 return null; 229 } 230 }, acc); 231 } 232 catch (PrivilegedActionException ex) { 233 throw ex.getException(); 234 } 235 } 236 else { 237 writeMethod.invoke(this.object, value); 238 } 239 } 240 catch (TypeMismatchException ex) { 241 throw ex; 242 } 243 catch (InvocationTargetException ex) { 244 PropertyChangeEvent propertyChangeEvent = 245 new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); 246 if (ex.getTargetException() instanceof ClassCastException) { 247 throw new TypeMismatchException(propertyChangeEvent, pd.getPropertyType(), ex.getTargetException()); 248 } 249 else { 250 throw new MethodInvocationException(propertyChangeEvent, ex.getTargetException()); 251 } 252 } 253 catch (Exception ex) { 254 PropertyChangeEvent pce = 255 new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); 256 throw new MethodInvocationException(pce, ex); 257 } 258 } }
通过对上面注入依赖代码的分析,我们已经明白了Spring IoC容器是如何将属性的值注入到Bean实例对象中去的:
(1).对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性。
(2).对于非集合类型的属性,大量使用了JDK的反射和内省机制,通过属性的getter方法(reader method)获取指定属性注入以前的值,同时调用属性的setter方法(writer method)为属性设置注入后的值。看到这里相信很多人都明白了Spring的setter注入原理。
至此Spring IoC容器对Bean定义资源文件的定位,载入、解析和依赖注入已经全部分析完毕,现在Spring IoC容器中管理了一系列靠依赖关系联系起来的Bean,程序不需要应用自己手动创建所需的对象,Spring IoC容器会在我们使用的时候自动为我们创建,并且为我们注入好相关的依赖,这就是Spring核心功能的控制反转和依赖注入的相关功能。
以上是关于Java面试Spring源码分析 —— Spring IoC的主要内容,如果未能解决你的问题,请参考以下文章
Java面试Spring源码分析 —— Spring IoC
Java面试Spring源码分析 —— Spring IoC