NonuniqueBeandDefinitionException-带策略模式的Spring DI

NonuniqueBeandDefinitionException-带策略模式的Spring DI,spring,dependency-injection,annotations,strategy-pattern,Spring,Dependency Injection,Annotations,Strategy Pattern,我正在尝试使用Spring实现基于策略模式的通信服务功能。我有以下课程: 接口-MessageService.java package com.xxx public Interface MessageService{ String sendMessage(String idOrNumber); } 实现类- package com.xxx public Interface MessageService{ String sendMessage(String idOrNu

我正在尝试使用Spring实现基于策略模式的通信服务功能。我有以下课程:

接口-MessageService.java

package com.xxx

public Interface MessageService{

    String sendMessage(String idOrNumber);

}
实现类-

package com.xxx

public Interface MessageService{

    String sendMessage(String idOrNumber);

}
1)EmailService.java

package com.xxx

@Component
public class EmailService implements MessageService{

        public String sendMessage(String idOrNumber){

    // Do some operation

    return "success"

    } 

}
package com.xxx

@Component
public class SmsService implements MessageService{

        public String sendMessage(String idOrNumber){

    // Do some operation

    return "success"

    } 

}
2)SmsService.java

package com.xxx

@Component
public class EmailService implements MessageService{

        public String sendMessage(String idOrNumber){

    // Do some operation

    return "success"

    } 

}
package com.xxx

@Component
public class SmsService implements MessageService{

        public String sendMessage(String idOrNumber){

    // Do some operation

    return "success"

    } 

}
通信工厂类

package com.xxx

@Component
public class CommunicationFactory {

    @Resource(name ="smsService")
    private SmsService smsService 


    @Resource(name ="emailService")
    private EmailService emailService;


    public MessageService getCommunicationChannel(String channel){

    MessageService messageService = null;

    if("sms".equals(channel){

    messageService = smsService;    

    }

    if("email".equals(channel){

    messageService = emailService;

    }

   return messageService;

}
我有一个邮件服务实现类

package com.xxx

@Component
@Service
public class CommunicationServiceImpl implements CommunicationService {

      @Autowired
      private MessageService messageService;

      CommunicationFactory communicationFactory;


      @Override
      public String sendCommunication(String idOrNumber){

        //Which implementation be called - SMS or EMAIL
        messageService = communicationFactory.getCommunicationChannel(channel);

        String statusMessage = messageService.sendMessage(idOrNumber);

        }

}
运行服务器时出现以下错误

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.xxx.MessageService com.xxx.CommunicationServiceImpl.messageService; nested exception is 

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.xxx.MessageService] is defined: expected single matching bean but found 2: smsService,emailService
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514) [spring-beans-

3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285) [spring-beans-

3.2.3.RELEASE.jar:3.2.3.RELEASE]
    ... 25 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.xxx.MessageService] is defined: expected single matching bean but found 2: 

smsService,emailService
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:863) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486) [spring-beans-

3.2.3.RELEASE.jar:3.2.3.RELEASE]
    ... 27 more 
我错在哪里?任何指针都会有帮助

试试这个

实现类-

1) EmailService.java

package com.xxx

@Component("emailService")
public class EmailService implements MessageService{

        public String sendMessage(String idOrNumber){

    // Do some operation

    return "success"

    } 

}
2) SmsService.java

package com.xxx

@Component("smsService")
public class SmsService implements MessageService{

        public String sendMessage(String idOrNumber){

    // Do some operation

    return "success"

    } 

}
问题在于:

@Autowired
private MessageService messageService;
可能的解决方案是@Autowired这两个服务

@Autowired
private MessageService smsService;
@Autowired
private MessageService emailService;
或者,如果你有同样的问题

@Autowired
@Qualifier("smsService")
private MessageService smsService;
@Autowired
@Qualifier("emailService")
private MessageService emailService;

我知道的最简单的实现是依赖注入的服务列表,并使用get方法获取负责的服务:

package com.xxx

@Component
public class CommunicationFactory {

    /**
     * This list would be ordered if the interface is implementing `org.springframework.core.Ordered` or an implementation declares `@org.springframework.core.annotation.Order`(in Spring 4)
     */
    @Autowired
    private List<MessageService> messageServices; 

    /**
     * @return the FIRST communication channel for the given channel
     */
    public MessageService getCommunicationChannel(String channel){
        for (MessageService ms : messageServices) {
            if (ms.supports(channel)) {
                return ms;
            }
        }
        return null; // or a default :)
    }

    /**
     * With this implementation you can even have multiple implementations firing a message if they support the given channel.
     * @return a list of communication channels that support the given channel
     */
    public List<MessageService> getCommunicationChannels(String channel){
        List<MessageService> supporting = new ArrayList<>();
        for (MessageService ms : messageServices) {
            if (ms.supports(channel)) {
                supporting.add(ms);
            }
        }
        return supporting;
    }
}
package com.xxx
@组成部分
公共类通信工厂{
/**
*如果接口正在实现`org.springframework.core.ordered`或实现声明`org.springframework.core.annotation.Order`(在Spring4中),则此列表将被排序
*/
@自动连线
私有列表服务;
/**
*@返回给定通道的第一个通信通道
*/
公共消息服务getCommunicationChannel(字符串通道){
用于(MessageService ms:messageServices){
如果(ms支持(通道)){
返回ms;
}
}
返回null;//或默认值:)
}
/**
*使用此实现,如果多个实现支持给定的通道,则您甚至可以让它们触发一条消息。
*@返回支持给定通道的通信通道列表
*/
公共列表getCommunicationChannels(字符串通道){
列表支持=新建ArrayList();
用于(MessageService ms:messageServices){
如果(ms支持(通道)){
支持。添加(ms);
}
}
回报支持;
}
}

Dani,我试过你的建议了。它也不起作用。我得到了同样的例外OK,我想你的问题在这里@Autowired private MessageService;,因为当Spring DI尝试注入该引用时,是两个具有相同接口的bean,而Spring无法决定哪一组。定义一个或重新实施这个方法。我喜欢帮助人们获得反对票。。。态度很好。在编辑之前,你的答案是没有解释的代码,这是错误的。默认情况下,bean的名称取自其类型的简单名称。因此,类型为
SmsService
的bean将被称为
SmsService
。在
@Component
注释中显式地给它命名更为清晰,但在这个特定示例中没有任何改变。编辑后,您的答案仍然缺少要点,您已将其作为评论发布。把它编辑进去,也许否决你的人会改变主意。我知道你告诉我的一切,但我是在帮助别人,第一眼我没有看到主要问题,但我不会投反对票给另一个用户,这是在帮助另一个用户,直到放弃这个帖子,当你帮助没有人投赞成票时,但是很快就会得到底片。。。我不理解这种态度,它让我不愿意帮助别人。你在服务课上没有资格。