【问题标题】:spring autowiring with unique beans: Spring expected single matching bean but found 2spring autowiring with unique beans: Spring 期望单个匹配 bean 但找到了 2
【发布时间】:2012-01-14 21:41:12
【问题描述】:

我正在尝试使用 Spring 为 webapp 自动装配一些 bean(用于依赖注入)。一个控制器 bean 包含另一个 bean,该 bean 又持有另一组 bean 的 hashmap。目前该地图只有一个条目。当我在 tomcat 中运行并调用服务时,我收到一条错误消息,指出第二个 bean(保存在控制器中)不是唯一的

No unique bean of type [com.hp.it.km.search.web.suggestion.SuggestionService] is defined: expected single matching bean but found 2: [suggestionService, SuggestionService]

我看不到我在哪里定义了两次 bean,但是我是 Spring 和自动装配的新手,所以我可能会遗漏一些基本的东西。下面列出的 xml 和 2 个类的源代码...

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"     xmlns:context="http://www.springframework.org/schema/context"     xmlns:mvc="http://www.springframework.org/schema/mvc"
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-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<context:component-scan base-package="com.hp.it.km.search.web.suggestion" />
<mvc:annotation-driven />
<context:annotation-config />

<bean id="SuggestionController" class="com.hp.it.km.search.web.suggestion.SuggestionController">
    <property name="service">
        <ref bean="SuggestionService" />
    </property>
</bean>

<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
    <property name="indexSearchers"> 
         <map>
            <entry key="KMSearcher"> <ref bean="KMSearcherBean"></ref></entry>
        </map>
    </property>
</bean>

<bean id="KMSearcherBean" class="com.hp.it.km.search.web.suggestion.SuggestionIndexSearcher">
      <constructor-arg index="0" value="KMSearcher" />
      <constructor-arg index="1" value="C://dev//workspace//search-restful-webapp//src//main//resources//indexes//keyword" />
</bean>

带有自动装配控制器和服务 bean 的类 asscoaites 在这里...

@Controller
public class SuggestionController {
private SuggestionService service;

@Autowired
public void setService(SuggestionService service) {
    this.service = service;
}

public SuggestionService getService() {
    return service;
}

还有……

@Component
public class SuggestionService {

private Map<String, IndexSearcher> indexSearchers = new HashMap<String,      IndexSearcher>();

@Autowired
public void setIndexSearchers(Map<String, IndexSearcher> indexSearchers) {
    this.indexSearchers = indexSearchers;
}

    public SuggestionService() {
    super(); }

请帮忙!

【问题讨论】:

    标签: spring spring-mvc dependency-injection annotations autowired


    【解决方案1】:

    问题是因为您有一个 SuggestionService 类型的 bean,它是通过 @Component 注释和 XML 配置创建的。正如 JB Nizet 所解释的,这将导致通过 @Component 创建一个名为“suggestionService”的 bean,并通过 XML 创建另一个名为“SuggestionService”的 bean。

    当您通过 @Autowired 引用 SuggestionService 时,在您的控制器中,Spring 默认“按类型”自动连接,并找到两个类型为“SuggestionService”的 bean

    您可以执行以下操作

    1. 从您的服务中删除 @Component 并依赖于通过 XML 的映射 - 最简单

    2. 从 XML 中移除 SuggestionService 并自动装配依赖项 - 使用 util:map 注入 indexSearchers 映射。

    3. 使用@Resource 而不是@Autowired 按名称选择bean。

       @Resource(name="suggestionService")
       private SuggestionService service;
      

        @Resource(name="SuggestionService")
        private SuggestionService service;
    

    两者都应该可以。第三个是脏修复,最好通过其他方式解决bean冲突。

    【讨论】:

    • 太棒了,我只是从服务类中删除了组件。然后得到一个关于控制器被注册两次的错误,并通过删除组件扫描来解决这个问题stackoverflow.com/a/4804417/491196感谢您的帮助
    【解决方案2】:

    如果你有 2 个相同类的 bean 自动连接到一个类,你应该使用 @Qualifier (Spring Autowiring @Qualifier example)。

    但您的问题似乎来自不正确的 Java 语法。

    你的对象应该以小写字母开头

    SuggestionService suggestion;
    

    你的setter也应该以小写开头,对象名也应该用大写

    public void setSuggestion(final Suggestion suggestion) {
        this.suggestion = suggestion;
    }
    

    【讨论】:

    • 您对设置器名称和大小写的权利。我必须在摆弄它以使其工作时错误地更改了它。不幸的是,这似乎不是问题。我已经用正确的二传手更新了上述问题。
    【解决方案3】:

    对我来说,这是让两个 bean 实现相同接口的情况。一个是为了单元测试而伪造的禁令,这与原始 bean 相冲突。 如果我们使用

    @component("suggestionServicefake")

    ,它仍然引用了建议服务。 所以我删除了@component,只使用了

    @Qualifier("suggestionServicefake")

    解决了问题

    【讨论】:

    • 如果您在测试类中使用属​​性@SpringBootTest(classes = SuggestionService.class),则相同。
    【解决方案4】:

    如果我没记错的话,使用 @Component 声明的 bean 的默认 bean 名称是其类的名称,它的第一个小写字母。这意味着

    @Component
    public class SuggestionService {
    

    声明一个类型为SuggestionService,名称为suggestionService 的bean。相当于

    @Component("suggestionService")
    public class SuggestionService {
    

    或到

    <bean id="suggestionService" .../>
    

    您正在 XML 中重新定义另一个相同类型但名称不同的 bean:

    <bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
        ...
    </bean>
    

    所以,要么在注解中指定 bean 的名称为 SuggestionService,要么在 XML 中使用 ID suggestionService(不要忘记同时修改 &lt;ref&gt; 元素,或者将其删除,因为不需要)。在这种情况下,XML 定义将覆盖注解定义。

    【讨论】:

    • 对不起,我不太理解你的第一句话,它写得有点奇怪。为什么“@Component public class SuggestionService {”和xml中的bean声明了两个bean?
    • 在您的最后一句话中,您说“要么指定注释中的 bean 名称为 SuggestionService”,这不是我所拥有的吗?我尝试将 xml bean 定义更改为小写,但问题仍然存在。谢谢你的帮助:)
    • 实际上你是非常正确的,但@Aravind A 的解决方案更接近最终让我通过它的原因。我只是从服务类中删除了组件。然后得到一个关于控制器被注册两次的错误,并通过按照这个解决方案删除组件扫描来解决这个问题stackoverflow.com/a/4804417/491196为您的帮助欢​​呼
    猜你喜欢
    • 2016-07-11
    • 2019-11-13
    • 1970-01-01
    • 2013-04-20
    • 2016-04-12
    • 2018-04-22
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多