从零开始造Spring03---使用构造器注入

举报
码农飞哥 发表于 2021/05/29 12:30:34 2021/05/29
【摘要】 前言 上一篇我们实现了setter注入,接下来我们要实现构造器注入。这是学习刘欣老师《从零开始造Spring》课程的学习笔记。 方案说明 类似于setter注入的处理方式,我们还是采用如下三步处理 - 设计一个数据结构 PropertyValue /ConstructorArgument - 解析XML,填充这个数据结构 - 利用这个数据结构做事情 具体实...

前言

上一篇我们实现了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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。