No qualifying bean of type ‘java.lang.String‘ available: expected at least 1 bean which qualifies

简介: No qualifying bean of type ‘java.lang.String‘ available: expected at least 1 bean which qualifies

一、问题复现和详细异常

今天一个同事在开发时给一个类(AServiceImpl)加了@AllArgsConstructor,希望通过private final 的方式将XxClassXxxClass注入到当前类:

@Service
@AllArgsConstructor
public class AServiceImpl implements AService{

    private final XxClass xxClass;

    private final XxxClass xxxClass;

    @Value("${my.value:myValue}")
    private String value;

    .....
}

运行时报错如下:

在这里插入图片描述

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1777) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1333) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1287) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1206) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:571) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.2.jar:5.3.2]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:923) ~[spring-context-5.3.2.jar:5.3.2]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588) ~[spring-context-5.3.2.jar:5.3.2]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.1.jar:2.4.1]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) [spring-boot-2.4.1.jar:2.4.1]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.4.1.jar:2.4.1]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) [spring-boot-2.4.1.jar:2.4.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) [spring-boot-2.4.1.jar:2.4.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309) [spring-boot-2.4.1.jar:2.4.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298) [spring-boot-2.4.1.jar:2.4.1]
    at com.saint.DemoTestApplication.main(DemoTestApplication.java:10) [classes/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1777)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1333)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1287)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
    ... 28 common frames omitted

二、原因分析

从报错提示可以看出是没有找到NoSuchBeanDefinition;根本原因是因为springioc容器加载bean默认使用无参构造进行初始化,就示例而言,需要用到只有一个入参的构造函数(AClassImpl(XsClass));

由于此处使用的是@AllArgsConstructor注解,所以对AClassImpl而言,只有一个构造函数(AClassImpl(XxClass, XxxClass, String)),而构造函数的第三个参数是用@Value注入导入的一个属性值,其并不会存在于Spring容器,所以报错。

源码分析

从报错信息找到出错的入口:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356)
在这里插入图片描述
这里可以看到获取到的AServiceImpl的构造函数中有三个入参,最后一个入参是String类型;

然后顺着报错日志的执行链路,找到
在这里插入图片描述

这里ConstructorResolver#resolveAutowiredArgument()方法会判断 用于解析指定参数的模板方法 是否支持被自动注入(autowired);非Class类型均不行。

抛出异常的源码位置如下:
在这里插入图片描述
因为采用构造函数注入属性的方式,属性是必须要存在于Spring容器的,所以这里检查参数必须性时会校验不通过(即不会提前return),进而报错;

三、解决方案

一般可以给AServiceImpl提供一个默认的构造方法来解决,但此处需要注入XxClassXxxClass,所以仅需生成一个只包含XxClassXxxClass两个参数的构造方法即可。
因此,我们选择使用@RequiredArgsConstructor注解来替换@AllArgsConstructor注解;

在这里插入图片描述

@RequiredArgsConstructor 和 @AllArgsConstructor的区别?

  • @RequiredArgsConstructor会将类的每一个final字段或者non-null字段生成一个构造方法
  • @AllArgsConstructor 生成一个包含所有字段的构造方法;
  • @NoArgsConstructor 生成无参的构造方法;

使用@RequiredArgsConstructor可以代替@Autowrited注解;而@RequiredArgsConstructor是根据构造器注入的,所以会有循坏依赖的问题。

@RequiredArgsConstructor循环依赖问题解决措施

有三种方式可以解决:

  1. 改为使用@Autowired注解做属性方法注入Bean;
    不过,Spring 从 4.0 开始, 就不推荐使用属性注入模式了,原因在于它可以让我们忽略掉一些代码可能变坏的隐患。
  2. 使用@RequiredArgsConstructor(onConstructor =@_(@Autowired) ),这样默认都是通过@Autowired注入Bean的;
  3. 使用@RequiredArgsConstructor(onConstructor_={@Lazy} ),做懒加载处理。
相关文章
|
4月前
|
JSON Java 数据格式
java调用服务报错415 Content type ‘application/octet-stream‘ not supported
java调用服务报错415 Content type ‘application/octet-stream‘ not supported
290 6
|
11月前
|
SQL 数据库
【YashanDB知识库】导入数据时报错:YAS-00008 type convert error:literal does not match format string
【YashanDB知识库】导入数据时报错:YAS-00008 type convert error:literal does not match format string
|
11月前
|
SQL 数据库
【YashanDB 知识库】导入数据时报错:YAS-00008 type convert error:literal does not match format string
【YashanDB 知识库】导入数据时报错:YAS-00008 type convert error:literal does not match format string
|
Java
Unable to obtain OffsetDateTime from TemporalAccessor: {},ISO resolved to 2024-11-26T20:55:26 of type java.time.format.Parsed
Unable to obtain OffsetDateTime from TemporalAccessor: {},ISO resolved to 2024-11-26T20:55:26 of type java.time.format.Parsed
490 0
|
JSON Java 数据格式
java调用服务报错415 Content type ‘application/octet-stream‘ not supported
java调用服务报错415 Content type ‘application/octet-stream‘ not supported
669 1
|
NoSQL Java Redis
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
224 0
|
JSON 前端开发 JavaScript
JSON parse error: Cannot deserialize value of type `java.lang.Integer` from Boolean value
这篇文章讨论了前端Vue应用向后端Spring Boot服务传输数据时发生的类型不匹配问题,即后端期望接收的字段类型为`int`,而前端实际传输的类型为`Boolean`,导致无法反序列化的问题,并提供了问题的诊断和解决方案。
JSON parse error: Cannot deserialize value of type `java.lang.Integer` from Boolean value
|
Java Spring 容器
Java SpringBoot 中,动态执行 bean 对象中的方法
Java SpringBoot 中,动态执行 bean 对象中的方法
277 0
|
Java Spring
Java SpringBoot Bean InitializingBean 项目初始化
Java SpringBoot Bean InitializingBean 项目初始化
388 0