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

Java面试Spring源码分析 —— Spring IoC

Spring源码分析专题——目录

详解Spring mvc工作原理及源码分析

【面试题解析】从 Vue 源码分析 key 的作用