最近遇到的启动报错如下:
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;
}
}