Spring常见异常说明

文章要点

  • Spring bean 的声明方式
  • Spring bean 的注入规则
  • Spring bean 的依赖查找规则
  • Spring bean 的名称定义方式和默认名称规则

XXX required a bean of type ‘XXX’ that could not be found.

这种情况,一般是因为没有在 Spring bean 容器中找到对应的 bean 。

Spring常见异常说明

bean 的声明

使用一个 bean,首先要声明一个 bean,使之交给 Spring 管理 声明一个 bean , 常用有如下几种方式

  • xml 声明
  • 注解声明

xml 声明

这种适用于非 SpringBoot 框架,老旧 Spring MVC 的框架使用形式。

现有架构常用于 dubbo bean 的声明,所有的 dubbo 引用和服务,都会声明成为一个 Spring bean


当你发现在 Spring bean 容器中无法找到一个 dubbo 服务的时候(这时候是引用 dubbo 服务),请从如下角度去思考问题:

  • dubbo 服务的注册/引用了吗 ?
  • dubbo 服务的配置属性 interface 写的对吗 ? 接口包打了吗?
  • dubbo 服务的引用配置属性 id 和 使用 dubbo 服务的地方匹配吗?

上述问题都解决后,就不会出现找不到 dubbo bean 的问题了

注解声明

声明成 Spring bean 有一个基础的注解 @Component ,这些都用与类上。


@Component  //这个类实例 已经交给 Spring 管理了
public class ComponentService {

}

其余我们常用的 @Service@Repository 等均继承这个基础注解,都可以声明一个类的实例为 Spring bean

其继承关系如下

Spring常见异常说明

注解声明-高级版

高级版注解声明需要依赖 @Configuration 注解

上章节中的 ComponentService 也可以用如下的方式去声明


@Configuration
public class TestConfiguration {

    //声明 ComponentService
    @Bean
    public ComponentService componentService() {
        //返回一个自定义实例,交给 Spring bean 管理
        return new ComponentService();
    }
}

这种返回一个自定义 bean 的类型,常用于项目组件配置,如 DataSourceJedisPool 等,业务系统一般用不到。

bean 的注入

我们可以使用 @Autowired (Spring)、 @Resource(JSR250规范) 、 @Inject(JSR330规范) 来进行注入

通常的,我们使用 @Autowired 足以满足各种注入场景,这里不再介绍另外两种。

在一个被 Spring 管理的类实例 (画重点) 当中 引用另外一个 Spring bean 的方式,即 bean 的注入方式,有如下三种:

  • 构造函数注入(官方推荐)
  • 字段注入
  • 方法注入

首先声明一个 bean,用于被别的 bean 注入

@Repository
public class TestRepository {
}

构造函数注入

@Service
public class TestService {

    private TestRepository testRepository;

    //@Autowired
    public TestService(TestRepository testRepository) {
        this.testRepository = testRepository;
    }
}

注意在构造函数上面, @Autowired 已经被我注释掉,原因如下:

As of Spring Framework 4.3,
an @Autowired annotation on such a constructor is no longer necessary
if the target bean defines only one constructor to begin with.

字段注入

@Service
public class TestService {
    @Autowired
    private TestRepository testRepository;
}

方法注入

@Service
public class TestService {

    private TestRepository testRepository;

    @Autowired
    public void setTestRepository(TestRepository testRepository) {
        this.testRepository = testRepository;
    }
}

以上方式可以混用,不拘泥于特定的形式。推荐构造函数注入而不是字段注入,是因为

  1. 字段注入完全依赖 Spring 的 IOC 功能,耦合性较高
  2. 防止不当使用时候,Spring bean 字段为空,这个是重点
  3. 当以也应该以 final 类型修饰字段时候,避免空指针的同时,也保证了依赖的不可变,不可变即安全
  4. 保证 Spring bean 的调用方调用的时候 bean 是完全初始化状态

至此,Spring bean 的注入已经 初入门径了。

Field xxx in xxx.xxx.xxx.xx required a single bean, but 2 were found

@Autowired 是根据接口进行注入,上述问题是因为在 依赖查找 中发现同一 Interface 的多个实例 bean

场景还原如下

  1. 声明一个接口类
public interface MultiService {
}
  1. 添加两个实现类
@Service
public class MultiServiceImpl implements MultiService{
}

@Service
public class MMultiService implements MultiService{
}
  1. 注入 MultiService
@Service
public class TestService {

    //这里进行注入,然而 Spring 发现了2个实例,默认规则没有匹配上,不知道该注入哪个了
    @Autowired
    private MultiService multiService;
}

那么,在一个接口有多个实现 bean 的情况下,如何注入自己想要的 bean ?

依赖查找的部分规则

  1. 首先根据类型查找(byType),如果查找结果唯一,就返回给依赖赋值。
  2. 如果依赖不唯一,则根据名称查找(byName),bean 名称不会重复。

byName的匹配规则:

  1. 如果有 @Qualifier 指定 依赖 bean 的名称,则拿指定名称与上述查找到的 bean 的名称进行匹配,匹配到则返回给依赖赋值
  2. 如果匹配不到,则拿 @Autowired 修饰的字段名或者方法参数名与 上述查找到的 bean 的名称匹配,匹配到则返回给依赖赋值
  3. 匹配不到则报 Field xxx in xxx.xxx.xxx.xx required a single bean, but 2 were found 错误

bean 名称的指定

在声明一个 bean 的时候,可以指定 bean 名称

//这里指定了bean name 为 componentService
@Component("componentService")
public class ComponentService {
}

//这里指定了bean name 为 multiService
@Service("multiService")
public class MultiServiceImpl implements MultiService{
}

//这里指定了bean name 为 mMultiService
@Service("mMultiService")
public class MMultiService implements MultiService{
}

如果没有指定 bean 名称,默认会以当前类名的首字母小写为 bean 名称

但是如果当前类的第二个字母仍然为大写,那就会以当前类名 为 bean 名称

MMultiService 的默认 bean 名称为 MMultiService
MultiServiceImpl 的默认 bean 名称为 multiServiceImpl

在使用一个 bean 的时候,也可以指定 bean 名称

@Service
public class TestService {

    @Autowired
    @Qualifier("MMultiService")  //指定 bean 名称
    private MultiService multiService;
}

org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘xxx’ for bean class [xxx.xx.xx.xx] conflicts with existing, non-compatible bean definition of same name and class [xxx.xxx.xxx]

这种就是 bean 名称定义重复了,知道异常栈中提示的错误 bean 名称并修改即可

The bean ‘xxx’, defined in class path resource [xx/xx/xx.class], could not be registered. A bean with that name has already been defined in file [xx\xx\xx.class] and overriding is disabled.

这种是 bean 被声明了多次,检查是否配置类编写错误,一般业务 bean 不会声明多次

这里可能会提示你通过设置 spring.main.allow-bean-definition-overriding=true 允许 bean 定义被覆盖

Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

请不要这么做!请找到 bean 声明冲突的地方,检查 bean 是否有特殊设置,根据业务进行取舍。不要简单覆盖 bean 定义了事

Original: https://www.cnblogs.com/qnlcy/p/15012134.html
Author: 去哪里吃鱼
Title: Spring常见异常说明

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/577912/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 安装clearos系统

    镜像下载、域名解析、时间同步请点击阿里云开源镜像站 一、clearos介绍 ClearOS是一个基于CentOS和Red Hat Enterprise Linux的简单,开源,价格…

    Linux 2023年5月27日
    097
  • 当前硬件版本不支持设备“nvme”。 vmx 未能启动虚拟机 2022-06-30T06:44:04.446Z In(05)+

    由于系统发生了dwm.exe内存泄露问题,为了处理就更新了一下系统,再 我打开VMware的时候运行不了虚拟机 再此记录一下: 发生此问题是硬件兼容性问题,解决办法: 根据VMMw…

    Linux 2023年6月8日
    0268
  • docker安装redis

    安装镜像 docker pull redis:7.0 下载配置文件 wget http://download.redis.io/redis-stable/redis.conf 修改…

    Linux 2023年6月7日
    0127
  • 云主机搭建WordPress个人博客

    安装宝塔控制面板 宝塔面板是一个简单、好用的面板,它的功能就是将LNMP和服务器的各种管理集成到一个可视化的WEB环境来管理,通过面板,我们普通人不需要掌握具体的技术,只需要动动鼠…

    Linux 2023年6月8日
    0112
  • 操作系统实现-boot.asm实现

    博客网址:www.shicoder.top微信:18223081347欢迎加群聊天 :452380935 这一次我们进入操作系统实现的真实编码, 这一次主要是完善对boot.asm…

    Linux 2023年6月13日
    0137
  • JavaScript 设计模式

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type&quo…

    Linux 2023年6月13日
    0121
  • Spring的循环依赖

    本文简要介绍了循环依赖以及Spring解决循环依赖的过程 循环依赖是指对象之间的循环依赖,即2个或以上的对象互相持有对方,最终形成闭环。这里的对象特指单例对象。 对象之间的循环依赖…

    Linux 2023年6月8日
    0148
  • Golang 实现 Redis(4): AOF 持久化与AOF重写

    AOF 持久化是典型的异步任务,主协程(goroutine) 可以使用 channel 将数据发送到异步协程由异步协程执行持久化操作。 在 DB 中定义相关字段: type DB …

    Linux 2023年5月28日
    0108
  • C++的vector的使用方法

    vector c++的vector的使用方法,创建,初始化,插入,删除等。 #include "ex_vector.h" #include #include #…

    Linux 2023年6月14日
    094
  • Redis从入门到精通:中级篇

    原文链接:http://www.cnblogs.com/xrq730/p/8944539.html,转载请注明出处,谢谢 本文目录 上一篇文章以认识Redis为主,写了Redis系…

    Linux 2023年5月28日
    0102
  • Ajax

    前戏 概念 异步提交,局部刷新 最大的优点是在页面不刷新的情况下可以与后端进行数据交互 用户注册无需点击按钮内部也可完成数据交互 同步交互:客户端发出一个请求后,需要等待服务器响应…

    Linux 2023年6月7日
    087
  • 浅谈缓存击穿、缓存穿透、缓存雪崩、缓存预热、缓存降级

    对于缓存,大家肯定都不陌生,不管是前端还是服务端开发,缓存几乎都是必不可少的优化方式之一。在实际生产环境中,缓存的使用规范也是一直备受重视的,如果使用的不好,很容易就遇到缓存击穿、…

    Linux 2023年6月14日
    0104
  • Linux的NIS配置

    快速命令 Server和Client设置NIS域名 nisdomainname nis_server echo ‘NISDOMAIN=nis_server’ >> /e…

    Linux 2023年6月6日
    0122
  • 复古冰雪传奇H5游戏详细图文架设教程

    前言 想体验复古传奇的热血PK吗?想体验满级VIP的尊贵吗?想体验一刀99999的爽快吗?各种极品炫酷时装、坐骑、翅膀、宠物通通给你,就在复古冰雪传奇H5! 本文讲解冰雪传奇架设教…

    Linux 2023年6月7日
    0113
  • Typora Ubuntu 安装

    官网方法 终端命令行安装 or use sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys BA300B77…

    Linux 2023年6月7日
    0101
  • Spring MVC处理日期字符串参数自动转换成后台Date类型

    当前台提交日期字符串到后台时,以字符串形式传输,若后台接收时采用Date类型,则会报格式转换错误的异常. 方式一: 将 @DateTimeFormat(pattern = &amp…

    Linux 2023年6月14日
    098
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球