从零开始造Spring03---使用构造器注入
前言
上一篇我们实现了setter注入,接下来我们要实现构造器注入。这是学习刘欣老师《从零开始造Spring》课程的学习笔记。
方案说明
类似于setter注入的处理方式,我们还是采用如下三步处理
- 设计一个数据结构 PropertyValue /ConstructorArgument
- 解析XML,填充这个数据结构
- 利用这个数据结构做事情
具体实现
首先我们来看下xml 配置:
<bean id="petStoreService" class="com.jay.spring.service.v3.PetStoreService"> <constructor-arg ref="accountDao"/> <constructor-arg ref="itemDao"/> <constructor-arg value="1"/> </bean>
- 1
- 2
- 3
- 4
- 5
- 6
xml 中定义了构造器的三个参数。
相关的类图:
在此处ValueHolder
类中的value 字段有可能是RuntimeBeanReference
,也有可能是TypedStringValue
。
我们可能会有这个疑问,为什么要弄一个ValueHolder
类呢,直接将Object
放在列表中不就行了么?
在Spring 中由于支持的ConstructorArgument
比较复杂。不能用一个Object来表达构造器中的值。所以我们需要提供一个类来处理。如图所示:
如图所示:有四种构造器配置,第一种是我们目前支持的,第二种可以指定数据类型,第三种可以直接指定name,第四种还可以指定索引。
关键代码:
数据结构:ConstructorArgument
public class ConstructorArgument { private final List<ValueHolder> argumentValues = new LinkedList<ValueHolder>(); public ConstructorArgument() { } public void addArgumentValue(ValueHolder valueHolder) { this.argumentValues.add(valueHolder); } public List<ValueHolder> getArgumentValues() { return Collections.unmodifiableList(this.argumentValues); } public int getArgumentCount() { return this.argumentValues.size(); } public boolean isEmpty() { return this.argumentValues.isEmpty(); } public static class ValueHolder { private Object value; private String type; private String name; public ValueHolder(Object value) { this.value = value; } public ValueHolder(Object value, String type) { this.value = value; this.type = type; } public ValueHolder(Object value, String type, String name) { this.value = value; this.type = type; this.name = name; } // get,set 方法省略 }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
XmlBeanDefinitionReader
类来解析xml文件
public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";
public void parseConstructorArgElements(Element beanEle, BeanDefinition beanDefinition) { Iterator iter = beanEle.elementIterator(CONSTRUCTOR_ARG_ELEMENT); while (iter.hasNext()) { Element ele = (Element) iter.next(); parseConstructorArgElement(ele, beanDefinition); } } public void parseConstructorArgElement(Element ele, BeanDefinition beanDefinition) { String typeAttr = ele.attributeValue(TYPE_ATTRIBUTE); String nameAttr = ele.attributeValue(NAME_ATTRIBUTE); Object value = parsePropertyValue(ele, beanDefinition, null); ConstructorArgument.ValueHolder valueHolder = new ConstructorArgument.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } beanDefinition.getConstructorArgument().addArgumentValue(valueHolder); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
我们接下来还需要解决的一个问题是,当类中有多个构造器时,该选择哪一个构造器呢?
类似于setter 注入中的BeanDefinitionValueResolve
类,我们同样设计了一个ConstructorResolver
用于将xml 解析出来的结构的变成实际的Bean的对象。
通过autowireConstructor
方法来创建对象,在创建对象的过程中就会将这三个参数的值注入到Bean中。
关键代码:
ConstructorResolver
类
public Object autowireConstructor(final BeanDefinition beanDefinition) { //找到一个可用的Constructor Constructor<?> constructorToUse = null; Object[] argsToUse = null; Class<?> beanClass = null; try { //装载BeanClass beanClass = this.beanFactory.getBeanClassLoader().loadClass(beanDefinition.getBeanClassName()); } catch (ClassNotFoundException e) { throw new BeanCreationException(beanDefinition.getID(), "nstantiation of bean failed, can't resolve class", e); }
// 通过反射的方式拿到Constructor Constructor<?>[] candidates = beanClass.getConstructors(); BeanDefinitionValueResolve valueResolve = new BeanDefinitionValueResolve(this.beanFactory); ConstructorArgument cargs = beanDefinition.getConstructorArgument();
// 类型转换 SimpleTypeCoverter typeCoverter = new SimpleTypeCoverter(); // 对候选的构造器进行循环 for (int i = 0; i < candidates.length; i++) { Class<?>[] parameterTypes = candidates[i].getParameterTypes();
// 构造器的参数个数与配置的参数个数不相等,则直接返回 if (parameterTypes.length != cargs.getArgumentCount()) { continue; }
// 可用对象 argsToUse = new Object[parameterTypes.length]; boolean result = this.valuesMatchTypes(parameterTypes, cargs.getArgumentValues(), argsToUse, valueResolve, typeCoverter); if (result) { constructorToUse = candidates[i]; break; } } if (constructorToUse == null) { throw new BeanCreationException(beanDefinition.getID(), "can't find a apporiate constructor"); } try { return constructorToUse.newInstance(argsToUse); } catch (Exception e) { throw new BeanCreationException(beanDefinition.getID(), "can't find a create instance using " + constructorToUse); } } /*** * * @param parameterTypes 参数类型 * @param valueHolders 参数对象 * @param argsToUse * @param valueResolve * @param typeCoverter * @return */ private boolean valuesMatchTypes(Class<?>[] parameterTypes, List<ConstructorArgument.ValueHolder> valueHolders, Object[] argsToUse, BeanDefinitionValueResolve valueResolve, SimpleTypeCoverter typeCoverter) { for (int i = 0; i < parameterTypes.length; i++) { ConstructorArgument.ValueHolder valueHolder = valueHolders.get(i);
// 获取参数的值,可能是TypedStringValue,也可能是RuntimeBeanReference Object originalValue = valueHolder.getValue(); try { //获得真正的值 Object resolvedValue = valueResolve.resolveValueIfNecessary(originalValue);
// 如果参数类型是int,但是值是字符串,例如"3",还需要转型
// 如果转型失败,则抛出异常,说明这个构造器不可用 Object convertedValue = typeCoverter.convertIfNecessary(resolvedValue, parameterTypes[i]);
// 转型成功,记录下来 argsToUse[i] = convertedValue; } catch (Exception e) { logger.error(e); return false; } } return true; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
文章来源: feige.blog.csdn.net,作者:码农飞哥,版权归原作者所有,如需转载,请联系作者。
原文链接:feige.blog.csdn.net/article/details/80959459
- 点赞
- 收藏
- 关注作者
评论(0)