《Spring攻略(第2版)》——1.4 解决构造程序歧义

简介: 当你为Bean指定一个或者多个构造程序参数时,Spring将试图在Bean类中查找对应的构造程序,并且传递用于Bean实例化的参数。但是,如果你的参数可以应用到超过一个构造程序,可能在构造程序匹配中造成歧义。在这种情况下,Spring可能无法调用你所预期的构造程序。

本节书摘来自异步社区《Spring攻略(第2版)》一书中的第1章,第1.4节,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.4 解决构造程序歧义

1.4.1 问题
当你为Bean指定一个或者多个构造程序参数时,Spring将试图在Bean类中查找对应的构造程序,并且传递用于Bean实例化的参数。但是,如果你的参数可以应用到超过一个构造程序,可能在构造程序匹配中造成歧义。在这种情况下,Spring可能无法调用你所预期的构造程序。

1.4.2 解决方案
你可以为元素指定type和index属性,帮助Spring查找预期的构造程序。

1.4.3 工作原理
现在添加一个新的构造程序到SequenceGenerator类,参数为prefix和suffix。

package com.apress.springrecipes.sequence;

public class SequenceGenerator {
   ...
   public SequenceGenerator(String prefix, String suffix) {
     this.prefix = prefix;
     this.suffix = suffix;
   }
}

在Bean声明中,你可以通过元素指定一个或者多个构造程序参数。Spring将尝试为该类寻找合适的构造程序,并传递用于Bean实例化的参数。回忆一下,中没有name属性,因为构造程序参数是基于位置的。

<bean id="sequenceGenerator"
   class="com.apress.springrecipes.sequence.SequenceGenerator">
   <constructor-arg value="30" />
   <constructor-arg value="A" />
   <property name="initial" value="100000" />
</bean>

Spring很容易为这两个参数找到一个构造程序,因为只有一个构造程序需要两个参数。假定你必须为SequenceGenerator添加另一个具有prefix和initial参数的构造程序。

package com.apress.springrecipes.sequence;

public class SequenceGenerator {
   ...
   public SequenceGenerator(String prefix, String suffix) {
     this.prefix = prefix;
     this.suffix = suffix;
   }

   public SequenceGenerator(String prefix, int initial) {
     this.prefix = prefix;
     this.initial = initial;
   }
}

为了调用这个构造程序,你建立下面的Bean声明,传递一个前缀和一个初始值。剩下的后缀通过设值方法注入。

<bean id="sequenceGenerator"
   class="com.apress.springrecipes.sequence.SequenceGenerator">
   <constructor-arg value="30" />
   <constructor-arg value="100000" />
   <property name="suffix" value="A" />
</bean>

但是,如果你现在运行应用程序,将会得到如下结果:

300A

301A

这个意外结果的起因是调用了第一个带有prefix和suffix参数的构造程序,而不是第二个。这是因为Spring默认将两个参数都解析为String类型,第一个构造程序不需要类型转换,所以被认定为最合适的。为了指定参数的预期类型,你必须设置中的type属性。

<bean id="sequenceGenerator"
   class="com.apress.springrecipes.sequence.SequenceGenerator">
   <constructor-arg type="java.lang.String" value="30" />
   <constructor-arg type="int" value="100000" />
   <property name="suffix" value="A" />
</bean>

现在,再为SequenceGenerator添加一个带有initial和suffix参数的构造程序,并相应修改Bean声明。

package com.apress.springrecipes.sequence;
public class SequenceGenerator {
   ...
   public SequenceGenerator(String prefix, String suffix) {
     this.prefix = prefix;
     this.suffix = suffix;
   }

   public SequenceGenerator(String prefix, int initial) {
     this.prefix = prefix;
     this.initial = initial;
   }

   public SequenceGenerator(int initial, String suffix) {
     this.initial = initial;
     this.suffix = suffix;
   }
}

<bean id="sequenceGenerator"
   class="com.apress.springrecipes.sequence.SequenceGenerator">
   <constructor-arg type="int" value="100000" />
   <constructor-arg type="java.lang.String" value="A" />
   <property name="prefix" value="30" />
</bean>

如果你再次运行应用程序,可能得到正确的结果,或者得到下列意外的结果:

30100000null

30100001null

这种不确定性的起因是Spring在内部对每个构造程序与参数的兼容性评分。但是在这个评分过程中,没有考虑参数出现在XML中的顺序。这意味着从Spring的角度看,第二个和第三个构造程序将得到同样的分数。选择哪一个构造程序取决于匹配的顺序。根据Java Reflection API,更精确地说是Class.getDeclaredConstructors()方法,返回的构造程序将是任意顺序的,可能与声明的顺序不同。所有这些因素综合起来,导致了构造程序匹配中的歧义。

为了避免这个问题,你必须通过的index属性明确指出参数的索引值。设置了type和index属性,Spring就能够准确地为Bean找到预期的构造程序。

<bean id="sequenceGenerator"
   class="com.apress.springrecipes.sequence.SequenceGenerator">
   <constructor-arg type="int" index="0" value="100000" />
   <constructor-arg type="java.lang.String" index="1" value="A" />
   <property name="prefix" value="30" />
</bean>

但是,如果你相当确定构造程序不会导致歧义,就可以忽略type和index属性。

相关文章
|
Java Spring
spring学习17-自动装配的歧义性
spring学习17-自动装配的歧义性
42 0
|
22天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
38 0
|
2月前
|
缓存 Java Maven
Spring Boot自动配置原理
Spring Boot自动配置原理
48 0
|
30天前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
106 0
|
3月前
|
Java Spring
springboot跨域配置
springboot跨域配置
31 0
|
1月前
|
前端开发 搜索推荐 Java
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
|
10天前
|
前端开发 Java 应用服务中间件
Springboot对MVC、tomcat扩展配置
Springboot对MVC、tomcat扩展配置
|
1天前
|
安全 Java 应用服务中间件
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
4 0
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
|
3天前
|
XML Java C++
【Spring系列】Sping VS Sping Boot区别与联系
【4月更文挑战第2天】Spring系列第一课:Spring Boot 能力介绍及简单实践
28 0
【Spring系列】Sping VS Sping Boot区别与联系