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

@限定符的Bean声明不起作用

郎经纶
2023-03-14

假设我有一个配置类(Jms队列配置,见下文)。在此类中,我想为整个应用程序配置多个队列。对于一个队列,没有问题。但是,当我添加第二个队列并尝试从服务(成员服务)中使用其中一个队列时,Spring启动会告诉我

com.example.notification.application.jms.JmsEventPublisher 中的构造函数的参数 1 需要一个 Bean,但找到 2 个: - 队列帐户通知:由类路径资源中的方法“队列帐户通知”定义 [com/示例/通知/应用程序/jms/Jms/JmsQueueConfig.class] - 队列通知到帐户:由类路径资源中的方法“队列通知到帐户”定义 [com/示例/通知/应用程序/jms/Jms/JmsQueueConfig.class]

行动:

考虑将其中一个豆子标记为@Primary,更新消费者以接受多个豆子,或使用@Qualifier来识别应该消费的豆子

这是我的配置类:

@Configuration
@EnableJms
@ImportAutoConfiguration(classes = {
        JmsAutoConfiguration.class,
        ActiveMQAutoConfiguration.class
})
public class JmsQueueConfig {

   @Value("${APP_QUEUE_ACCOUNT_TO_NOTIFICATION}")
   private String queueAccountToNotificationName;

   @Value("${APP_QUEUE_NOTIFICATION_TO_ACCOUNT}")
   private String queueNotificationNameToAccount;

   @Bean
   @Qualifier("q1")
   public Queue queueAccountToNotification() {
      return new ActiveMQQueue(queueAccountToNotificationName);
   }

   @Bean
   @Qualifier("q2")
   public Queue queueNotificationToAccount() {
      return new ActiveMQQueue(queueNotificationNameToAccount);
   }

   @Bean
   public MessageConverter jacksonJmsMessageConverter() {
      MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
      converter.setTargetType(MessageType.TEXT);
      converter.setTypeIdPropertyName("_type");
      return converter;
   }

   @Bean
   @Qualifier("p1")
   public EventPublisher eventPublisher(JmsTemplate jmsTemplate) {
      return new JmsEventPublisher(jmsTemplate, new ActiveMQQueue(queueAccountToNotificationName));
   }

   @Bean
   public MessageConverter messageConverter() {
      return new JmsMessageConverter();
   }
}

我的服务:

@Service
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
@Slf4j
public class MemberService {

   @Autowired
   @Qualifier("q1")
   Queue q;

   @Qualifier("p1")
   EventPublisher eventPublisher;

   public void createMemberSubscription(final Member member) {
      final MembershipSubscriptionEvent event = new MembershipSubscriptionEvent(UUID.randomUUID().toString(), member.getEmail());
      //eventPublisher.publish(event);
      log.info("createMemberSubscription");
   }

   public void removeMemberSubscription(final Member member) {
      final MembershipRemovalEvent event = new MembershipRemovalEvent(UUID.randomUUID().toString());
      //eventPublisher.publish(event);
      log.info("removeMemberSubscription");
   }
}

我是Spring生态系统的新手,可能还没有很好地理解@Autowired和绑定。任何好的文件或例子将不胜感激。在Spring和SoF上,我没有找到任何这样的文档。

更新时间:Jms事件发布者类

@Component
@FieldDefaults(level = AccessLevel.PRIVATE)
@Slf4j
@AllArgsConstructor
public class JmsEventPublisher implements EventPublisher {

   final JmsTemplate jmsTemplate;
   final Destination destination;

   @Override
   public void publish(DomainEvent event) {
      jmsTemplate.convertAndSend(destination, event);
      log.trace("Sent event. [destination={}, event={}]", destination, event);
   }
}

共有3个答案

薛英卫
2023-03-14

将< code >最终目的地destination更改为< code >最终目的地q1,应该可以工作。我也有同样的问题,但它对我有效。

桓兴腾
2023-03-14

我认为您误解了@Qualifier
从文档中,“在自动连接时,此注释可能用于字段或参数,作为候选bean的限定符。”

在您的情况下,@Qualifier没有任何意义。

@Bean
   @Qualifier("q1")
   public Queue queueAccountToNotification() {
      return new ActiveMQQueue(queueAccountToNotificationName);
   }

相反,你应该这样做

@Bean(name = "q1")
   public Queue queueAccountToNotification() {
      return new ActiveMQQueue(queueAccountToNotificationName);
}


@Bean(name = "q2")
   public Queue queueNotificationToAccount() {
      return new ActiveMQQueue(queueNotificationNameToAccount);
   }

同样,删除事件发布者(...) 上的@Qualifier

这并不能解决所有问题。:)

正如异常指出的,spring不能自动连接JmsEventPublisher中的< code>Destination字段。因为它有两个类型为Destination的beans和q2)。< br >要解决这个问题,您可以做的是。

将@Primary放在其中一个bean声明上,然后使用@Qualifier

@Primary
@Bean(name = "q1")
   public Queue queueAccountToNotification() {
      return new ActiveMQQueue(queueAccountToNotificationName);
}


public class JmsEventPublisher implements EventPublisher {

   final JmsTemplate jmsTemplate;
   @Qualifier("q1")
   final Destination destination;

     ..........

 }

底线是,为了让@Qualifier在多个相同类型的豆子的情况下工作,你需要把@Primary

另一种选择是不使用@Main,您可以将变量命名为Bean名称,然后Spring会自动为您注入正确的bean。即。

public class JmsEventPublisher implements EventPublisher {

  final JmsTemplate jmsTemplate;
  final Destination q1; // q1 or q2
  .....
}

类似地在会员服务中

public class MemberService {

  @Autowired
  Queue q1; // q1 or q2
  .....

}
韦星文
2023-03-14

要纠正已接受的答案,你对@限定词用法的理解是正确的。它可以在两种情况下使用。它可以与@Bean配置方法一起使用,为Bean提供限定符。如果未提供,则默认为bean名称。

它还可以用于注入目标,即带有@Autowired或@Inject注释的方法或字段。在这种情况下,如果找到多个bean,它可以帮助Spring自动连接基础设施根据限定符(@bean方法提供)筛选匹配注入目标的bean候选

错误的原因是

@AllArgsConstructor
public class JmsEventPublisher implements EventPublisher

@AllArgsConstructor将生成以下构造函数

public JmsEventPublisher(JmsTemplate jmsTemplate, Destination destination){
   //body
 }

Spring将尝试通过构造函数自动连接JmsEventPublisher,因为它有一个不是无参数构造函数的构造函数。但是,类型Destination的参数匹配两个类型Queue的beans。

解决方案是使用显式构造器。即删除@AllArgsConstructor并定义constrctor,如下所示

public JmsEventPublisher(JmsTemplate jmsTemplate, @Qualifier("q1")Destination destination){
   //body
 }

或使用field或setter注入代替,即删除@AllArgsConstructor并注入字段或setter方法

public class JmsEventPublisher implements EventPublisher {

   private JmsTemplate jmsTemplate;
   @Qualifier("q1")
   private Destination destination;

 }
 类似资料:
  • 我正试图编写代码,从一个Android应用程序发送一条短信,但当我试图发送短信时,它给我返回了错误: 我检查了,但我拥有清单中的权限,如下所示: null null 我在网上搜索了一下,但是所有的错误都是关于语法的,你能帮我一下吗?

  • 请说出这段代码有什么问题。

  • 问题内容: 我想知道是否有人可以在CSS中!important声明 无法 覆盖内联样式时放些权威参考摘要。 问题答案: 确定哪些样式相互替代涉及许多因素。样式声明出现在 级联中 的位置越低,则它在定位元素时 越具体 ,则与其他样式的权衡就越大。 这是样式继承的CSS2标准: 如果级联产生一个值,请使用它。 否则,如果属性是继承的,则使用父元素的值,通常是计算值。 否则,请使用属性的初始值。每个属性

  • 我生成doc与发音插件和它的工作,我添加了一个源目录添加额外的文件到类路径编译(maven-编译器插件).发音不工作与this.how我解决这个问题?我得到这个错误:[ERROR]未能执行目标org.codehaus.enunciate: maven-en

  • 我发现以下错误: 错误:变量或字段“foo”声明为void 错误:“a”之前应为“)” 错误:在'b'之前预期')' 在函数“int main()”中:错误:“foo”未在此范围内声明