How to listen to topic using spring boot jms

前端 未结 3 1125
被撕碎了的回忆
被撕碎了的回忆 2021-01-05 07:19

I am trying to listen to topic using the below snippet. However its listening to queue by default. There is no xml config in this case. I am completely relying on annotation

相关标签:
3条回答
  • 2021-01-05 07:32

    In Spring Boot's Application.properties, try setting the following property:

    spring.jms.pub-sub-domain=true
    

    Then, use this property for the container factory that you are using to listen to the topic.

    0 讨论(0)
  • 2021-01-05 07:39

    The answer marked correct is ALMOST correct. It still wont work because:

    factory.setPubSubDomain(true) 
    

    must come AFTER:

    configurer.configure(factory, connectionFactory);
    

    Otherwise the pubSubDomain flag being set to true is lost when configuring the defaults and that factory instance will still work with queues and not topics.

    0 讨论(0)
  • 2021-01-05 07:42

    I just took the complete Spring boot example from : https://github.com/spring-guides/gs-messaging-jms/

    In this it is created for sending and receipt of messages from a queue. To Change this to a topic , you have to set the Pub-Sub property in the Factory instance.

    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.jms.annotation.EnableJms;
    import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
    import org.springframework.jms.config.JmsListenerContainerFactory;
    import org.springframework.jms.connection.CachingConnectionFactory;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
    import org.springframework.jms.support.converter.MessageConverter;
    import org.springframework.jms.support.converter.MessageType;
    
    import javax.jms.ConnectionFactory;
    
    @SpringBootApplication
    @EnableJms
    public class JmsSampleApplication {
    
    public void registerBeans(ConfigurableApplicationContext context ){
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(JmsTemplate.class);
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    
        builder.addPropertyValue("connectionFactory", cachingConnectionFactory);      // set property value
        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
        factory.registerBeanDefinition("jmsTemplateName", builder.getBeanDefinition());
    }
    
    @Bean
    public JmsListenerContainerFactory<?> topicListenerFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setPubSubDomain(true);
        // This provides all boot's default to this factory, including the message converter
        configurer.configure(factory, connectionFactory);
        // You could still override some of Boot's default if necessary.
        return factory;
    }
    
    @Bean
    public JmsListenerContainerFactory<?> queueListenerFactory(ConnectionFactory connectionFactory,
                                                               DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        //factory.setPubSubDomain(true);
        // This provides all boot's default to this factory, including the message converter
        configurer.configure(factory, connectionFactory);
        return factory;
    }
    
    @Bean // Serialize message content to json using TextMessage
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(JmsSampleApplication.class, args);
    
        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
    
        // Send a message with a POJO - the template reuse the message converter
        System.out.println("Sending an email message.");
        jmsTemplate.convertAndSend("mailbox.topic", new Email("info@example.com", "Hello"));
        jmsTemplate.convertAndSend("mailbox.queue", new Email("info@example.com", "Hello"));
    
        }
    }
    

    The listener

    package org.springboot.jms;
    
    import org.springframework.jms.annotation.JmsListener;
    import org.springframework.stereotype.Component;
    
    /**
     * Created by RGOVIND on 10/20/2016.
     */
    @Component
    public class HelloTopicListener {
    
        @JmsListener(destination = "mailbox.topic", containerFactory = "topicListenerFactory")
        public void receiveTopicMessage(Email email) {
            System.out.println("Received <" + email + ">");
        }
    
        @JmsListener(destination = "mailbox.queue", containerFactory = "queueListenerFactory")
        public void receiveQueueMessage(Email email) {
            System.out.println("Received <" + email + ">");
        }
    }
    

    Once this is done , you are all set to subscribe to the topic of choice.

    There are multiple approaches to this of course , you can have a map of beans for different jmsTemplates , each of which can be used when you need them based on queue or topic. The template & beans can be instantiated in a method you choose to like discussed in this SO Question. Hope it helps

    0 讨论(0)
自定义标题
段落格式
字体
字号
代码语言
提交回复
热议问题