在不阻塞主线程的情况下启动 JMSListener

Start a JMSListener without block the main thread

我正在尝试通过 spring 引导启动一个应用程序,该应用程序具有 JMSListener 以连接到外部 ActiveMQ,即使 ActiveMQ 已关闭,此应用程序也需要启动。

我在连接中使用了故障转移传输协议,但是当我启动应用程序时主线程被阻塞,而 JMS 尝试建立连接并且应用程序在建立第一个连接之前不会启动。

我正在尝试这个解决方案,我在其中扩展 DefaultMessageListenerContainer 并在将释放主线程的新线程中将 start 方法覆盖到 运行。

Consumer.java

@SpringBootApplication
public class Consumer {

    public static void main(String[] args) {
        SpringApplication.run(Consumer.class, args);
        System.out.println("Consumer Start");
    }
}

接收器

@Component
public class Receiver {

    @Bean
    public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new MyListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    @JmsListener(destination = "mailbox", containerFactory = "myFactory")
    public void receiveMessage(String email) {
        System.out.println("Received <" + email + ">");
    }

}

MyListenerContainer.java

public class MyListenerContainer extends DefaultMessageListenerContainer {

    @Override
    public void start() throws JmsException {
        new Thread(() -> {
            super.start();
        }).start();
    }
}

MyListenerContainerFactory.java

public class MyListenerContainerFactory extends DefaultJmsListenerContainerFactory {

    @Override
    protected DefaultMessageListenerContainer createContainerInstance() {
        return new MyListenerContainer();
    }
}

1º问题: 这个解决方案有效,但我不确定这是否不会破坏 spring bean 的开始,因为我在创建连接之前完成了 start 方法。这会破坏 spring 引导中的 bean 创建过程吗?

2º问题: 除此之外,如果我在同一个应用程序中有一个 JMSListener 和一个 JMSProducer,它们会尝试使用相同的连接还是使用不同的连接?

如果有人有更好的不同解决方案,请分享。

感谢您抽出宝贵时间并致以最诚挚的问候

贝尔纳多·内维斯

  1. 使用 factory.setAutoStartup(false); 可能更干净,这将阻止 Spring 尝试启动容器;准备好后使用 container.start()(在任何你想要的线程上)。
@Autowired
private JmsListenerEndpointRegistry registry;

...

    registry.start(); // starts all containers
    // or
    registry.getListenerContainer(myContainerId).start();
  1. 他们将使用相同的连接。