Spring Boot异常org.springframework.beans.factory.NoUniqueBeanDefinitionException

最近遇到的启动报错如下:

Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.apexsoft.livebos.dao.FileStorageDao’ available: expected single matching bean but found 2:

原因:

Spring Boot异常org.springframework.beans.factory.NoUniqueBeanDefinitionException:没有可用的合格Bean类型:预期匹配单个Bean,但是匹配到了多个,当该bean被自动装配时与Spring Boot应用程序上下文中的两个或多个加载的Bean匹配时,就会发现该异常。

Spring Boot允许从一个接口或抽象类创建两个或多个bean。如果该bean是自动注入的,当有两个或多个bean是自动注入的时候,该bean无法自动连接,就会产生异常org.springframework.beans.factory.NoUniqueBeanDefinitionException

举例:

当为一个类创建两个或多个bean或为接口实现的两个或多个类对象创建时,将创建异常。在此示例中,创建了两个类的接口。如果使用@Autowired注释自动连接接口,则无法自动连接Bean。

简单的说就是你有一个A接口,你B、C类都实现了A接口,然后你注入了A,编译的时候它不知道你是要使用A下的B还是C,然后就报错了(解决办法就是指定要注入的具体B还是C)

动物接口:

package com.yawintutor;

public interface Animal {
	public String getName();
}

狮子类实现动物接口:

package com.yawintutor;

import org.springframework.stereotype.Component;

@Component
public class Lion implements Animal{
	@Override
	public String getName() {
		return "Lion";
	}
}

老虎类实现动物接口:

package com.yawintutor;

import org.springframework.stereotype.Component;

@Component
public class Tiger implements Animal{
	@Override
	public String getName() {
		return "Tiger";
	}
}

测试动物园类

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Zoo {
	@Autowired
	public Animal animal;
}

输出:

2020-12-09 11:50:40.365  WARN 25121 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo': Unsatisfied dependency expressed through field 'animal'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yawintutor.Animal' available: expected single matching bean but found 2: lion,tiger
2020-12-09 11:50:40.372  INFO 25121 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-09 11:50:40.394 ERROR 25121 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field animal in com.yawintutor.Zoo required a single bean, but 2 were found:
	- lion: defined in file [/SpringBootBean/target/classes/com/yawintutor/Lion.class]
	- tiger: defined in file [/SpringBootBean/target/classes/com/yawintutor/Tiger.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

解决方案1

Spring Boot自动连线可与Java命名约定变量名称一起使用。如果使用与Java命名约定变量的已实现类名匹配的变量创建了Bean,则注释@Autowired可以使用已实现的类进行自动装配。异常将得到解决。

在下面的示例中,变量的名称为lion。“ lion”是“ Lion”类的Java约定变量的名称。这就是@Autowired注解使用Lion类Bean对象自动装配变量的原因。

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	@Autowired
	public Animal lion;
}

解决方案2

Spring Boot的自动注入将根据数据类型工作。如果类的数据类型与加载的Bean相匹配,则Bean将自动连接到变量。因此,不要使用接口或抽象类名称,而要使用实现的类来自动装配bean。

在下面的示例中,使用实现的类创建可变动物。自动装配会创建“ Lion”类型的bean,并将其分配给变量“ animal”

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	@Autowired
	public Lion animal;
}

解决方案3

如果自动连线中包含了其中一个引入的类,则该类应使用@Primary进行注释。带注释的@Primary类被视为自动装配中的默认类。@Autowired批注将加载@Primary bean并为其添加接口或抽象变量。

在下面的示例中,@ Primary批注用于注册为默认bean。@Autowired批注将使用Bean自动连接变量。

package com.yawintutor;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Component
@Primary
public class Lion implements Animal{
	@Override
	public String getName() {
		return "Lion";
	}
}

解决方案4

Spring Boot批注@Qualifier用于从多个bean中选择一个bean。@Qualifier批注将被配置为与bean名称匹配。@Autowired注解使用限定符的名称来匹配并加载Bean。

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	@Autowired
	@Qualifier("lion")
	public Animal animal;
}

解决方案5

如果自动装配使用类方法进行配置,则将限定符与方法参数一起使用。下面的示例将显示带有方法的注解@Autowired。方法参数注入注解@Qualifier。

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	private Animal animal;

	@Autowired
	public vod setAnimal(@Qualifier("lion") Animal animal){
		this.animal = animal;
	}
}

参考:
NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值