一尘不染

带有@Qualifier的@Bean声明不起作用

spring-boot

可以说我有一个配置类(JmsQueueConfig,请参见下文)。在此类中,我想为整个应用程序配置多个队列。对于一个队列,没有问题。但是,当我添加第二个队列并尝试从服务(MemberService)使用这些队列之一时,Spring-
boot会告诉我

com.example.notification.application.jms.JmsEventPublisher中的构造函数的参数1需要一个bean,但是找到2:-queueAccountToNotification:由类路径资源[com
/ example / notification / application / jms
/中的方法’queueAccountToNotification’定义[JmsQueueConfig.class]-queueNotificationToAccount:由类路径资源[com
/ example / notification / application / jms /
JmsQueueConfig.class]中的方法’queueNotificationToAccount’定义

行动:

考虑将其中一个Bean标记为@Primary,更新使用者以接受多个Bean,或使用@Qualifier标识应使用的Bean

这是我的配置类:

@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上,我还没有找到任何此类文档。

更新: JmsEventPublisher类

@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);
   }
}

阅读 1545

收藏
2020-05-30

共1个答案

一尘不染

我认为您@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);
   }

同样除去@QualifiereventPublisher(...)

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

如异常所示,spring无法自动Destination绑定JmsEventPublisher中的字段。因为它有两个类型为Destination(q1和q2)的bean。
为了解决这个问题,您可以做的是。

放入@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在多个相同类型的bean的情况下工作,您需要@Primary

另一个选择是使用@Primary而不是@Primary,可以将变量命名为与Bean名称完全相同的名称,然后spring将自动为您注入正确的Bean。即

public class JmsEventPublisher implements EventPublisher {

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

类似地在MemberService中

public class MemberService {

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

}
2020-05-30