Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect JMS queue using JNDI with Spring Boot

I had a hard time figuring out how to implement a Spring Boot JMS Listener, listening to an ActiveMQ queue within a JBoss application server. Therefore I choose to post a question and answer it with my final solution, hoping it could save some of you a few hours.

like image 551
Thomas Joeisseint Avatar asked Dec 19 '18 12:12

Thomas Joeisseint


1 Answers

ActiveMQ is supported by Spring Boot autoconfiguration, but since it was inside the JBoss server Spring Boot was failing to connect ActiveMQ. In fact you need to define connectionFactory and jmsListenerContainerFactory beans yourself by doing a lookup on the JNDI provider.

@Configuration
@EnableJms
public class ActiveMqConnectionFactoryConfig {

  @Value("${broker.url}")
  String brokerUrl;

  @Value("${borker.username}")
  String userName;

  @Value("${borker.password}")
  String password;

  @Value("${queue}")
  String queueName;

  private static final String INITIAL_CONTEXT_FACTORY = "org.jboss.naming.remote.client.InitialContextFactory";
  private static final String CONNECTION_FACTORY = "jms/RemoteConnectionFactory";


  @Bean
  public ConnectionFactory connectionFactory() {
    try {
      System.out.println("Retrieving JMS queue with JNDI name: " + CONNECTION_FACTORY);
      JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
      jndiObjectFactoryBean.setJndiName(CONNECTION_FACTORY);

      jndiObjectFactoryBean.setJndiEnvironment(getEnvProperties());
      jndiObjectFactoryBean.afterPropertiesSet();

      return (QueueConnectionFactory) jndiObjectFactoryBean.getObject();

    } catch (NamingException e) {
      System.out.println("Error while retrieving JMS queue with JNDI name: [" + CONNECTION_FACTORY + "]");
    } catch (Exception ex) {
      System.out.println("Error");
    }
    return null;
  }

  Properties getEnvProperties() {
    Properties env = new Properties();
    env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
    env.put(Context.PROVIDER_URL, brokerUrl);
    env.put(Context.SECURITY_PRINCIPAL, userName);
    env.put(Context.SECURITY_CREDENTIALS, password);
    return env;
  }

  @Bean
  public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) {

    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    JndiDestinationResolver jndiDestinationResolver = new JndiDestinationResolver();

    jndiDestinationResolver.setJndiEnvironment(getEnvProperties());
    factory.setDestinationResolver(jndiDestinationResolver);
    return factory;
  }

Then if you want to consume the queue you just define your JMS consumer class with a method annotated with @JmsListener(destination = "${queue}")

 @JmsListener(destination = "${queue}")
  public void receive(Message message) {
    System.out.println("Received Message: " + message);
  }

Hope that helps save a few hours of research ;)

Cheers

like image 50
Thomas Joeisseint Avatar answered Sep 25 '22 14:09

Thomas Joeisseint