介绍
本文主要介绍前文Spring依赖注入(2)的遗留问题
- 自动装配Bean歧义问题
自动装配Bean歧义问题
Spring自动装配bean时, 必须确保bean的唯一、无歧义性, 否则Spring自动装配时无法确定具体应该装配的bean, 报出bean不唯一异常, org.springframework.beans.factory.NoUniqueBeanDefinitionException。
示例描述
我们定义了一个向量运算的接口, 同时定义了向量求和和向量点乘的类实现该接口,两个类均使用@Component的注解, 在使用@Autowired注解加载向量运算时存在歧义导致加载失败。
向量运算接口
package com.notepad.springnote.inject; /** * Description: 2个向量之间的运算接口 * <p> * Create: 2018/6/30 10:41 * * @author Yang Meng(eyangmeng@163.com) */ public interface BaseVectorOperation { Double process(Double[] v1, Double[] v2) throws Exception; }
向量求和
package com.notepad.springnote.inject; import org.springframework.stereotype.Component; /** * Description: 向量求和 * <p> * Create: 2018/6/30 10:49 * * @author Yang Meng(eyangmeng@163.com) */ @Component public class VectorSum implements BaseVectorOperation { @Override public Double process(Double[] v1, Double[] v2) throws Exception { if (v1.length != v2.length) throw new AssertionError(); double res = 0; for (int i = 0; i < v1.length; i++) { res += v1[i] + v2[i]; } return res; } }
向量点乘
package com.notepad.springnote.inject; import org.springframework.stereotype.Component; /** * Description: 2个向量之间的点乘 * <p> * Create: 2018/6/30 10:44 * * @author Yang Meng(eyangmeng@163.com) */ @Component public class VectorDot implements BaseVectorOperation { @Override public Double process(Double[] v1, Double[] v2) throws Exception { if (v1.length != v2.length) throw new AssertionError(); double res = 0.0; for (int i = 0; i < v1.length; i++) { res += v1[i] * v2[i]; } return res; } }
代码自测
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = InjectConfig.class) public class BaseVectorOperationTest { // 加载bean歧义 @Autowired private BaseVectorOperation operation; @Test public void testProcess() throws Exception { Double[] v1 = {0.1, 0.2}; Double[] v2 = {0.1, 0.3}; assert v1.length == v2.length; System.out.println(operation.process(v1, v2)); } }
解决方法
定义bean时添加@Primary注解标记首选,当加载时优先选择加载注解的bean。示例如下:
// 将向量点乘标记为首选bean, 在加载时出现BaseVectorOperation时优先选用向量点乘 @Primary @Component public class VectorDot implements BaseVectorOperation {....}
加载bean时添加@Qualifier注解限定装配的bean。如果没有指定限定符的bean将会给定一个默认的限定符(bean名称的基础上首字母小写, 例如:VectorDot的限定符为 vectorDot ),加载方法如下:
@Autowired // 加载向量求和 @Qualifier(value = "vectorSum") private BaseVectorOperation operation;
定义bean时添加@Qualifier创建限定符: 针对解决方法2限定符和bean的名称是紧耦合的, 一旦改动容易出现错误, 为此通过自定义解决, 示例如下:
// 为向量点乘自定义限定符, 后续的加载使用dot即可加载VectorDot @Qualifier("dot) @Component public class VectorDot implements BaseVectorOperation {....}
Github代码
参考
Spring In Action(第四版). 第三章