当前位置: 首页 > 知识库问答 >
问题:

使用@Qualifier注释抛出“NonuiquebeandeFinitionException”(找到多个相同类型的bean)

方航
2023-03-14

我收到了错误

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.storage.StorageService' available: expected single matching bean but found 2: service2,service1

尝试启动Spring应用程序时。

这是由我创建的两个类(StorageService)引起的,它们分别是我创建的实现和接口。我在类级别本身命名了两个服务类,即服务(service1)和服务(service2),我正在尝试自动连接控制器构造函数中的每个类,并通过在构造函数中的每个参数上直接使用限定符注释来指定所需的服务,但我仍然收到NonuiquebeandeFinitionException错误。

我只是希望Spring能够通过使用限定符注释来区分这两个bean。

存储服务

package hello.storage;

import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Path;
import java.util.stream.Stream;

public interface StorageService {

    void init();

    void store(MultipartFile file);

    Stream<Path> loadAll();

    Path load(String filename);

    Resource loadAsResource(String filename);

    void deleteAll();

}

文件系统存储服务

package hello.storage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

@Service("service1")
public class FileSystemStorageService implements StorageService {

    private final Path rootLocation;

    @Autowired
    public FileSystemStorageService(StorageProperties properties) {
        this.rootLocation = Paths.get(properties.getLocation());
    }

    @Override
    public void store(MultipartFile file) {
        try {
            if (file.isEmpty()) {
                throw new StorageException("Failed to store empty file " + file.getOriginalFilename());
            }
            Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename()));
        } catch (IOException e) {
            throw new StorageException("Failed to store file " + file.getOriginalFilename(), e);
        }
    }

    @Override
    public Stream<Path> loadAll() {
        try {
            return Files.walk(this.rootLocation, 1)
                    .filter(path -> !path.equals(this.rootLocation))
                    .map(path -> this.rootLocation.relativize(path));
        } catch (IOException e) {
            throw new StorageException("Failed to read stored files", e);
        }

    }

    @Override
    public Path load(String filename) {
        return rootLocation.resolve(filename);
    }

    @Override
    public Resource loadAsResource(String filename) {
        try {
            Path file = load(filename);
            Resource resource = new UrlResource(file.toUri());
            if(resource.exists() || resource.isReadable()) {
                return resource;
            }
            else {
                throw new StorageFileNotFoundException("Could not read file: " + filename);

            }
        } catch (MalformedURLException e) {
            throw new StorageFileNotFoundException("Could not read file: " + filename, e);
        }
    }

    @Override
    public void deleteAll() {
        FileSystemUtils.deleteRecursively(rootLocation.toFile());
    }

    @Override
    public void init() {
        try {
            Files.createDirectory(rootLocation);
        } catch (IOException e) {
            throw new StorageException("Could not initialize storage", e);
        }
    }
}

AltFileSystemStorageService

package hello.storage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

@Service("service2")
public class AltFileSystemStorageService implements StorageService {

    // Exactly the same as "FileSystemStorageService" this is just for testing/learning
}

FileUploadController

package hello;

import java.io.IOException;
import java.util.stream.Collectors;

import hello.storage.AltFileSystemStorageService;
import hello.storage.FileSystemStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import hello.storage.StorageFileNotFoundException;
import hello.storage.StorageService;

@Controller
public class FileUploadController {

    private final StorageService storageService;
    private final StorageService altStorageService;

    @Autowired
    public FileUploadController(@Qualifier("service1") FileSystemStorageService storageService,
                                @Qualifier("service2") AltFileSystemStorageService altStorageService)
    {
        this.storageService = storageService;
        this.altStorageService = altStorageService;
    }

    // Controller specific methods

}

应用

package hello;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import hello.storage.StorageProperties;
import hello.storage.StorageService;

@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    CommandLineRunner init(StorageService storageService) {
        return (args) -> {
            storageService.deleteAll();
            storageService.init();
        };
    }
}

我相信抛出异常是因为FileUploadController,但我也认为我正确使用了@Qualifier注释。

我已经检查了SO的多个示例,但似乎没有任何效果。

>

@Spring中的限定符批注不起作用

Spring@自动接线和@限定符[关闭]

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

Description:

Parameter 0 of method init in hello.Application required a single bean, but 2 were found:
    - service2: defined in file [/UploadFiles/initial/target/classes/hello/storage/AltFileSystemStorageService.class]
    - service1: defined in file [/UploadFiles/initial/target/classes/hello/storage/FileSystemStorageService.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

[WARNING] 
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:542)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'init' defined in hello.Application: Unsatisfied dependency expressed through method 'init' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.storage.StorageService' available: expected single matching bean but found 2: service2,service1
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
    at hello.Application.main(Application.java:17)
    ... 6 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.storage.StorageService' available: expected single matching bean but found 2: service2,service1
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:221)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1229)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760)
    ... 25 more
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.838 s
[INFO] Finished at: 2019-09-07T13:21:10-04:00
[INFO] Final Memory: 34M/120M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.6.RELEASE:run (default-cli) on project gs-uploading-files: An exception occurred while running. null: InvocationTargetException: Error creating bean with name 'init' defined in hello.Application: Unsatisfied dependency expressed through method 'init' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.storage.StorageService' available: expected single matching bean but found 2: service2,service1 -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

共有2个答案

张华池
2023-03-14

这个问题被问了很长时间,也得到了解决。但我想告诉你作者犯的一个大错,这使他无法找到根本原因。

根据堆栈跟踪,它告诉我们问题出在init方法中,而不是作者所认为的控制器中。这张错误的支票使他远离了根本原因。

Parameter 0 of method init in hello.Application required a single bean, but 2 were found:
    - service2: defined in file [/UploadFiles/initial/target/classes/hello/storage/AltFileSystemStorageService.class]
    - service1: defined in file [/UploadFiles/initial/target/classes/hello/storage/FileSystemStorageService.class]
詹正浩
2023-03-14

我认为您应该在CommandLineRunner中添加限定符:

@Bean
CommandLineRunner init(@Qualifier("service1") StorageService storageService)
 类似资料:
  • 问题内容: 我试图在一个元素上拍两个或多个相同类型的注释,在这种情况下是方法。这是我正在使用的近似代码: 编译以上内容时,javac抱怨重复的注释: 这样根本不可能重复注释吗?从学步上讲,上面的两个@Foo实例是否由于内容不同而不同吗? 如果上述方法不可行,有哪些可能的解决方法? 更新:我被要求描述我的用例。开始。 我正在建立一种语法糖化机制,以“映射” POJO到文档存储(例如MongoDB)。

  • 这个应用程序的每个JVM应该使用相同的数据库吗?否则跟踪令牌不会在同一个应用程序中“共享”? 如何在运行传奇的相同应用程序中拆分事件?一个saga类型或saga实例是否总是在同一个应用程序上处理(直到它被关闭,所以另一个实例负责它)? 还是每个JVM都接收事件,并且每个相同类型的传奇都将运行?(并导致发送重复命令和错误) 等。还有很多问题。

  • 我有一个类CustomerProfile,它映射到一个表CUST_PROFILE。我们需要在一个单独的表中维护关闭的概要文件,该表将具有相同的模式。我在SO中读过很多问题,特别是下面的问题(下面有一个总结了很多类似问题的答案) 每个实体Hibernate两个表 从中我可以理解,使用MappedSuperclass以外的注释很难获得相同的结果。但可以使用xml映射。 我之所以不愿使用Mappedsu

  • 问题内容: 我如何使用类型提示来注释一个返回总是返回两个值的函数:a和a ?提示很接近,除了将返回值类型限制为元组,而不是生成器或其他可迭代类型。 我主要是好奇的,因为我想注释一个用于返回多个值的函数,如下所示: 通常函数喜欢做这样的事情(它返回一个元组),但我喜欢的类型暗示要足够灵活,以取代发电机或列表或别的东西返回的元组。 问题答案: 您总是返回 一个 对象;使用只需返回一个元组。 是的,完全

  • 我有一个类,它有两个相同类型的最终字段,我需要在第二个字段中注入if属性

  • 问题内容: 我喜欢基于构造函数的注入,因为它允许我进行注入的字段。我还喜欢注释驱动的注入,因为它简化了我的操作。只要没有两个相同类型的参数,就可以用标记构造函数,并且一切正常。例如,我有一个课: 以及具有以下内容的应用程序上下文: 应该有一种在类的构造函数上指定bean ID的方法,但是我在文档中找不到它。是否有可能,或者我是否梦想着不存在的解决方案? 问题答案: 是按类型(在这种情况下);用于按