在运行时使用 SmartLifecycle 添加队列时出现问题 [英] Problem adding queues using SmartLifecycle at runtime

查看:47
本文介绍了在运行时使用 SmartLifecycle 添加队列时出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,这是与 这个

我创建了一个案例,其中 ListenerContainer 实际上在 @Bean 之前以阶段 0 运行,即使它具有阶段 Integer.MAX_INT.代码如下:

I have created a case where ListenerContainer is actually run before @Bean with phase 0, even though it has phase Integer.MAX_INT. Here is the code:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.GenericApplicationContext;

@SpringBootApplication
public class RuntimeRegisterApp {

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

  @Bean
  public CachingConnectionFactory cachingConnectionFactory(){
    CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setAddresses("10.10.121.199:35682");
    cachingConnectionFactory.setUsername("guest");
    cachingConnectionFactory.setPassword("guest");
    return cachingConnectionFactory;
  }

  @Bean
  public DirectRabbitListenerContainerFactory directFactory(ConnectionFactory cachingConnectionFactory) {
    DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();
    factory.setConnectionFactory(cachingConnectionFactory);
    return factory;
  }

  @RabbitListener(bindings = {
      @QueueBinding(value = @Queue(value = "SomeQueue", durable = "false", autoDelete = "true"),
          exchange = @Exchange(value = "SomeEX", ignoreDeclarationExceptions = "true"),
          key = "SomeKey")
  },
      containerFactory = "directFactory"
  )
  public void onMessage(String msg){
    System.out.println("Received " + msg);
  }

  public void onMessage2(String msg){
    System.out.println("Received 2 " + msg);
  }

  @Bean
  public org.springframework.amqp.core.Queue someQueue(){
    return QueueBuilder.nonDurable("some1").build();
  }

  @Bean
  public DirectMessageListenerContainer container(DirectRabbitListenerContainerFactory directFactory){
    DirectMessageListenerContainer container = directFactory.createListenerContainer();
    container.setConsumersPerQueue(2);
    container.setMessageListener(
        message -> System.out.println("BEAN CONTAINER " + message.toString()));
    container.setQueues(someQueue());
    return container;
  }

  @Bean
  public RabbitAdmin rabbitAdmin(){
    return new RabbitAdmin(cachingConnectionFactory());
  }

  @Bean
  SmartLifecycle dynamicRegister(GenericApplicationContext applicationContext,
      DirectMessageListenerContainer container,
      DirectRabbitListenerContainerFactory directFactory,
      RabbitAdmin rabbitAdmin){

    return new SmartLifecycle() {

      private boolean running;

      private void dynamicallySetQueues(){
        org.springframework.amqp.core.Queue q1 = QueueBuilder
            .nonDurable("mySomeQueue")
            .build();

        rabbitAdmin.declareQueue(q1);

        applicationContext.registerBean(org.springframework.amqp.core.Queue.class, () -> q1);

        List<String> queues = new ArrayList<>(Arrays.asList(container.getQueueNames()));
        queues.add(q1.getName());


        //THIS ONE WORKS SINCE WE USE FACTORY AND SET QUEUES BEFORE START
        DirectMessageListenerContainer container1 = directFactory.createListenerContainer();
        container1.setQueueNames(queues.toArray(new String[0]));
        container1.setMessageListener(message -> System.out.println("INNER CONTAINER" + message.toString()));
        container1.start();

        //THIS ONE WORKS SINCE WE ONLY ADD QUEUES
        container.addQueueNames(q1.getName());

        //SETTING QUEUES HERE FAILS, SINCE CONTAINER ALREADY RUNNING
        //BUT IT SHOULD NOT RUN, SINCE THIS IS PHASE 0 ?
        //I GUESS SINCE IT IS NEEDED HERE IT RUNS ANYWAY ?
        container.setQueueNames(queues.toArray(new String[0]));
      }

      @Override
      public void start() {
        dynamicallySetQueues();
        running = true;
      }

      @Override
      public void stop() {
        running = false;
      }

      @Override
      public int getPhase() {
        return 0; //return 0 so we add queues before ListenerContainer starts
      }

      @Override
      public boolean isRunning() {
        return running;
      }
    };
  }
}

我猜它正在运行,因为它是 SmartLifecycle bean 的实际依赖项.我在这里看到的唯一解决方法是 setAutostart(false) 在 Container 上,然后在 SmartLifecycle bean 内部调用 container.start() 在设置队列名称.

I guess that it is running since it is actual dependency of SmartLifecycle bean. Only workaround I can see here is to setAutostart(false) on Container, and then inside SmartLifecycle bean call container.start() after setting the queue names.

推荐答案

你说得对;生命周期处理器在启动当前 bean 之前启动任何依赖 bean...

You are correct; the lifecycle processor starts any dependent beans before starting the current bean...

        for (String dependency : dependenciesForBean) {
            doStart(lifecycleBeans, dependency, autoStartupOnly);
        }

...实际上,添加依赖会减少依赖 bean 的阶段.

...in effect, adding the dependency decreases the dependent bean's phase.

您的解决方案可能是最简单的.

Your solution is probably the simplest.

这篇关于在运行时使用 SmartLifecycle 添加队列时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆