Start a JMSListener without block the main thread

Bernardo Neves :

I'm trying to start an application with spring boot that have a JMSListener to connect to an external ActiveMQ, this application need to start even the ActiveMQ is down.

I'm using a failover transport protocol in the connection, but when I start the application the main thread is blocked while the JMS try to establish the connection and the application don't start until the first connection is made.

I was trying this solution, where I extend the DefaultMessageListenerContainer and override the start method to run in a new thread that will free the main thread.

Consumer.java

@SpringBootApplication
public class Consumer {

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

Receiver

@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º Question: This solution work but I'm not sure if this does not break anything in the start of spring beans since I'm finishing the start method before the connection is created. Can this break the bean creation process in spring boot?

2º Question: In additional to this if I have in the same application a JMSListener and a JMSProducer they will try to use the same connection or they use different ones?

If someone has a different solution that is better please share.

Thank you for the time and best regards

Bernardo Neves

Gary Russell :
  1. It's probably cleaner to use factory.setAutoStartup(false); which will prevent Spring from attempting to start the container; use container.start() when you are ready (on whatever thread you want).
@Autowired
private JmsListenerEndpointRegistry registry;

...

    registry.start(); // starts all containers
    // or
    registry.getListenerContainer(myContainerId).start();
  1. They will use the same connection.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=166172&siteId=1