解决 required a single bean, but 2 were found的spring注入bean错误

2023-10-29

背景介绍

个人定义了一个interface,为了抽象与规范使用泛型进行约束,名字举例为 ITestService.java

public interface ITestService<T extends BaseTest>{
	void test();
}

通过不同的业务场景需要进行不同的实现,比如 ITestServiceImplOne.java、ITestServiceImplTwo.java
举例:(注:TestOne extends BaseTest)

@Service
public class ITestServiceImplOneimplements ITestService<TestOne>{
	@Override
	void test(){
	}
}

这时,我需要在另外一个abstract类 TestAbstract.java中通过@Autowired注入ITestService

public abstract class TestAbstract<T extends BaseTest>{
 	@Autowired
    private ITestService<T> iTestService;
	
	public void test(T test){
		iTestService.test();
	}
}

此时由于我们使用的均是泛型,不知道具体指向的实例是哪个Bean,就会报错:
required a single bean, but 2 were found

个人理解

造成此问题的原因是:
IOC容器中有两个bean 分别是 ITestServiceImplOne、ITestServiceImplTwo,在调用的abstract类中,注入的为interface类,由于是泛型,并没有指向具体的实例bean,所以导致Autowired注入时不知道注入哪一个。

解决思路

方式一 优先级使用

可以考虑使用 @Primary 注解,比如在 ITestServiceImplOne 上添加,这时就优先使用此类

方式二 默认值使用

分别对 ITestServiceImplOne 、ITestServiceImplTwo 的 @Service 注解添加默认value值 ,
例如 @Service(“testServiceImplOne”)、@Service(“testServiceImplTwo”)
并且在 abstract 类中注入 ITestService 的地方添加 @Qualifier注解,并使用你想要的默认service
例如:

public abstract class TestAbstract<T extends BaseTest>{
 	@Autowired
 	@Qualifier("testServiceImplOne")
    private ITestService<T> iTestService;
	
	public void test(T test){
		iTestService.test();
	}
}

方式三 工厂模式设计思路(推荐)

我们都知道IOC是一个容器,而我们抽象的思想就是动态的使用工厂里的bean。
那么我们可不可以通过工厂模式指定我们想要使用的动态bean呢?答案是肯定的。
如何实现呢?
设想,如果我给每一个service打上一个flg标记,通过标记对应上泛型的属性是不是就可以搞定呢?

第一步,分别给每一个service泛型的test类打上标记。
先说明下我的 BaseTest 是一个 abstract 类。
这个时候我在 BaseTest 定义一个 abstract 方法,例如:

abstract String getBeanName();

在每一个泛型的实例类中实现该方法并返回不同的值。

第二步,分别给每一个service绑定flg标记并对应到泛型实例上
在 ITestService 中定义抽象方法,并与泛型的实例类的标记值保持一致

abstract String getBeanName();

以 ITestServiceImplOne 为例:

@Override
public String getBeanName(){
	return "testOne";
}

第三步,使用工厂设计模式定义Factory类
通过工厂获取我们想要的具体的service
示例代码:

@Component
public class TestFactory {

    private Map<String, ITestService> iTestServiceMap = new HashMap<>();

    @Autowired
    private WebApplicationContext webApplicationContext;

    public ITestService getITestService(String serviceBeanName) {
        return iTestServiceMap .get(serviceBeanName);
    }
    @PostConstruct
    public void register()  {
        Map<String, ITestService> map = webApplicationContext.getBeansOfType(ITestService.class);
        if(map != null && !map.isEmpty()){
            map.entrySet().forEach(entry -> {
                iTestServiceMap .put(entry.getValue().getBeanName(), entry.getValue());
            });
        }
    }
}

第四步,使用工厂模式
在TestAbstract类中不再直接注入ITestService而是注入定义的工厂,通过工厂获取ITestService类
示例代码

public abstract class TestAbstract<T extends BaseTest>{
 	@Autowired
    private TestFactory  testFactory ;
	
	public void test(T test){
		ITestService iTestService = testFactory.getITestService(test.getBeanName());
		iTestService.test();
	}
}

重在思想理解
如有问题,欢迎指点

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决 required a single bean, but 2 were found的spring注入bean错误 的相关文章

随机推荐

  • OpenCV - 车牌识别新手入门级讲解

    目录 0 引言 1 MFC中的车牌显示 2 车牌定位 3 字符提取 4 文字识别 5 文字预测 0 引言 第一次使用OpenCV完成一个完整的功能 有所收获 特此记录 这篇博客中的车牌识别功能比较简单 只能识别一般的蓝色车牌 只能识别拍摄较
  • Python中数据处理(npz、npy、csv文件;元组、列表、numpy数组的使用)

    目录 1 npz文件 2 npy文件 3 csv文件 4 列表 元组 numpy矩阵 列表 元组 不可变列表 Numpy数组 Numpy矩阵 1 npz文件 npz是python的压缩文件 读取文件 独取文件 读取当前文件夹下的data的m
  • jdk11配置javafx

    下载javafx的jar包 网站 https openjfx io 进去之后直接点下载 下载对应操作系统的版本 这里下载windows系统的 下载完之后是一个压缩包文件 解压 刚开始写好之后是这样的 找不到javafx的类 接下来导入jar
  • [机器学习与scikit-learn-37]:算法-分类-支持向量机-核函数与线性不可分-原理

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 123804551 目录 前言 第1章
  • junit测试案例

    JUnit测试是以Java写成的 使用Java测试Java软件形成一个介于测试及程序代码间的无缝 seamless 边界 在测试的控制下测试变成整个软件的扩充同时程序代码可以被重整 Java编译器的单元测试静态语法检查可已帮助测试程序并且确
  • TCP的三次握手与四次挥手理解及面试题

    序列号seq 占4个字节 用来标记数据段的顺序 TCP把连接中发送的所有数据字节都编上一个序号 第一个字节的编号由本地随机产生 给字节编上序号后 就给每一个报文段指派一个序号 序列号seq就是这个报文段中的第一个字节的数据编号 确认号ack
  • LeetCode: 91 解码方法

    方法一 用递归来做 这道题一开始以为是简单的递归问题 按照从前往后的顺序递归 总是在 10 这个输入上报错 按照从后向前的方法递归 应对短序列没有问题 但是面对长序列 因为存在大量重复计算 所以超时 如果用递归来做 应该用记忆化递归 cla
  • 【linux操作系统】——页表的深入理解

    作者 努力学习的少年 个人简介 双非大二 一个正在自学c 和linux操作系统 写博客是总结知识 方便复习 目标 进大厂 如果你觉得文章可以的话 麻烦你给我点个赞和关注 感谢你的关注 在每一个进程中 每个进程都有自己的虚拟内存空间 该内存空
  • 【SpringBoot】yml配置时区的配置项

    时区参数定义yml文件 environment TZ Asia Shanghai services systemManage image ports 8082 8082 environment spring profiles active
  • git回滚reset到指定分支

    在git中我们经常会遇到提交代码之后需要进行回滚的操作 可以通过git reset 命令进行回滚 首先找到需要回滚到的提交的commit id 然后通过 git reset hard 老的commit id 然后更新当前分支到最新提交 gi
  • 16 单台与多台机器配置https证书、全站https(以discuzx为例)

    HTTPS 1 HTTPS基本概述 为什么需要使用HTTPS 因为HTTP不安全 当我们使用http网站时 会遭到劫持和篡改 如果采用https协议 那么数据在传输过程中是加密的 所以黑客无法窃取或者篡改数据报文信息 同时也避免网站传输时信
  • angularJS1笔记-(1)-多控制器

    前端写好 div div div div
  • ubuntu安装lxml

    ubuntu安装lxml 可以参考一下 先执行 sudo apt get install libxml2 dev libxslt dev python dev 然后执行 sudo easy install lxml
  • 用户态、内核态的基本概念及切换方式

    用户态 内核态 一 用户态 内核态的基本概念 二 用户态 内核态的切换方式 一 用户态 内核态的基本概念 用户态 用户态运行的进程可以直接读取用户程序的数据 内核态 内核态运行的进程或程序几乎可以访问计算机的任何资源 不受限制 两者最重要的
  • MySQL8.0.15重置密码 windows10 64位 (忘记密码或者无法登录)

    经过多次试验最终 重置密码的步骤如下 1 以管理员身份 打开命令窗口cmd 输入命令 net stop mysql 停止MySQL服务 2 开启跳过密码验证登录的MySQL服务 输入命令 mysqld console skip grant
  • Linux Ubuntu 设置脚本开机启动

    主要参考下面这个博客 ubuntu18开机启动脚本 但是要注意 有的ubuntu里面并不存在这个目录 在一开始的 vim etc systemd system rc local service 这一步就会失败 比如我的系统 最后我使用fin
  • runtime engine VM的一些随想

    这篇文章还是我在写作的新书 新时期的Node js 入门的一部分 一些比喻 我们可以通过一些现实的比喻来理解接下来要讲述的概念 苏联是社会主义的一种运行时 这大概是我这辈子能想到的最贴切的比喻了 笑 社会主义只是一种思想 可以看做是一门编程
  • 控制流图怎么画

    一 什么是控制流图 控制流图 Control Flow Graph CFG 也叫控制流程图 是一个过程或程序的抽象表现 是用在编译器中的一个抽象数据结构 由编译器在内部维护 代表了一个程序执行过程中会遍历到的所有路径 它用图的形式表示一个过
  • FPGA实现图像二值形态学滤波——腐蚀膨胀

    一 二值图像 二值图像 Binary Image 是指图像上的每一个像素只有两种可能的取值或灰度等级状态 简言之 在图像中灰度等级只有两种0或255 黑或白 二 形态学 形态学 即数学形态学 Mathematical Morphology
  • 解决 required a single bean, but 2 were found的spring注入bean错误

    背景介绍 个人定义了一个interface 为了抽象与规范使用泛型进行约束 名字举例为 ITestService java public interface ITestService