文章要点

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

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

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

bean 的声明

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

  • xml 声明
  • 注解声明

xml 声明

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 声明一个 Spring bean -->
<bean id="testService" class="com.example.demo.TestService"/>
</beans>

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

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

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

注解声明

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


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

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

其继承关系如下

注解声明-高级版

高级版注解声明需要依赖 @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 定义了事

Spring常见异常说明的更多相关文章

  1. spring常见异常

    1.ClassNotFoundException: org.springframework.dao.support.DaoSupport(解决:导入spring-tx) 2.NoClassDefFou ...

  2. spring集成Junit做单元测试及常见异常解决办法

    spring-test依赖包 <!--Spring-test --> <!-- https://mvnrepository.com/artifact/org.springframew ...

  3. spring使用aop需要的jar包,和常见异常

    3.0以后spring不再一起发布aop依赖包,需要自己导入: 必须包: 这几个jar包分别为 1.org.springframework.aop-3.1.1.RELEASE  这个是spring的 ...

  4. Spring学习总结(14)——Spring10种常见异常解决方法

    在程序员生涯当中,提到最多的应该就是SSH三大框架了.作为第一大框架的Spring框架,我们经常使用. 然而在使用过程中,遇到过很多的常见异常,我在这里总结一下,大家共勉. 一.找不到配置文件的异常 ...

  5. 【转】Hibernate 常见异常

    转载地址:http://smartan.iteye.com/blog/1542137 Hibernate 常见异常net.sf.hibernate.MappingException        当出 ...

  6. Spring10种常见异常解决方法

    在程序员生涯当中,提到最多的应该就是SSH三大框架了.作为第一大框架的Spring框架,我们经常使用. 然而在使用过程中,遇到过很多的常见异常,我在这里总结一下,大家共勉. 一.找不到配置文件的异常 ...

  7. Hibernate 常见异常

    Hibernate 常见异常net.sf.hibernate.MappingException        当出现net.sf.hibernate.MappingException: Error r ...

  8. Spring启动异常: cvc-elt.1: Cannot find the declaration of element 'beans'(转)

    Spring启动异常: cvc-elt.1: Cannot find the declaration of element 'beans' 2008-09-07 22:41 今天把在线聊天室代码改了下 ...

  9. orcal 数据库 maven架构 ssh框架 的全xml环境模版 及常见异常解决

    创建maven项目后,毫不犹豫,超简单傻瓜式搞定dependencies(pom.xml 就是maven的依赖管理),这样你就有了所有你要的包 <project xmlns="http ...

随机推荐

  1. Python3.x 基础练习题100例(71-80)

    练习71: 题目: 编写input()和output()函数输入,输出5个学生的数据记录. 程序: N = 5 # stu # num : string # name : string # score ...

  2. Java并发之AQS原理剖析

    概述: AbstractQueuedSynchronizer,可以称为抽象队列同步器. AQS有独占模式和共享模式两种: 独占模式: 公平锁: 非公平锁: 共享模式: 数据结构: 基本属性: /** ...

  3. golang快速入门(六)特有程序结构

    提示:本系列文章适合对Go有持续冲动的读者 阅前须知:在程序结构这章,更多会关注golang中特有结构,与其他语言如C.python中相似结构(命名.声明.赋值.作用域等)不再赘述. 一.golang ...

  4. [leetcode] (周赛)868. 二进制间距

    868. 二进制间距 读懂题意就出来了 class Solution { public int binaryGap(int N) { String s = Integer.toBinaryString ...

  5. Docker学习(14) Docker容器的数据管理

    Docker容器的数据管理 Docker容器的数据卷 重要: Docker的数据卷容器 Docker数据卷的备份和还原

  6. Mapper注解与MapperScan注解

    1.Mapper注解 在接口类上添加@Mapper,在运行时动态代理生成实现类 @Mapper public interface UserDao { // User getUser(); } 如果想要 ...

  7. GVS灵动系列家族上新 | 稳住,我们能“银”

    用天赐的色库 给生活增加些艺术的气息 生活本应多点探索的乐趣 今天 GVS灵动系列家族流光银(白玻璃) 全新上线 用灵感朝圣自然之道 邂逅另一种柔性美学 与早前的经典黑.星耀灰 和而不同,美美与共 携 ...

  8. 从实力的角度出发来思考这道AOP题目

    文/楠木大叔 技术更迭,一往无前.技术人总是要不断学习以适应社会的发展和行业对我们的要求.每隔一段时间,就会有纷至沓来的新技术,新知识,新概念,我们应该如何应对,是被逼到墙角,还是主动出击? 导读 从 ...

  9. Netty 框架学习 —— ByteBuf

    概述 网络数据的基本单位总是字节,Java NIO 提供了 ByteBuffer 作为它的字节容器,但这个类的使用过于复杂.Netty 的 ByteBuf 具有卓越的功能性和灵活性,可以作为 Byte ...

  10. 05:JS(01)

    内容概要 JavaScript编程语言开头 数值类型 字符类型 布尔值 null与undefined 对象 数组 自定义对象 流程控制 函数 内置对象 时间对象 正则对象 JSON对象 BOM操作(j ...