Reputation: 111
Spring Boot JMS Topic not working properly it behave like queue.
Sample code
Application
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
JMSConfig
@Configuration
@EnableJms
public class JMSConfig {
private static final String JMS_BROKER_URL = "vm://embedded?broker.persistent=false,useShutdownHook=false";
public static final String JMS_TOPIC_MAIL = "mailbox.topic";
@Bean
// Serialize message content to json using TextMessage
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
@Bean
public ActiveMQConnectionFactory amqConnectionFactory() {
return new ActiveMQConnectionFactory(JMS_BROKER_URL);
}
@Bean
public CachingConnectionFactory connectionFactory() {
return new CachingConnectionFactory(amqConnectionFactory());
}
@Bean
public ActiveMQTopic destinationTopic() {
return new ActiveMQTopic(JMS_TOPIC_MAIL);
}
@Bean
public JmsTemplate jmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory());
// jmsTemplate.setDefaultDestination(destinationTopic());;
jmsTemplate.setDefaultDestinationName(JMS_TOPIC_MAIL);
jmsTemplate.setConnectionFactory(connectionFactory());
jmsTemplate.setMessageConverter(jacksonJmsMessageConverter());
return jmsTemplate;
}
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory(
ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setPubSubDomain(true);
factory.setConnectionFactory(connectionFactory());
// 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;
}
}
Here listeners are
First listener
@Component
public class JMSTopicListener1 {
@JmsListener(destination = JMSConfig.JMS_TOPIC_MAIL, containerFactory = "jmsListenerContainerFactory")
public void receiveTopicMessage(Email email) {
System.out.println("JMSTopicListener#1 Received <" + email + ">");
}
}
Second listener
@Component
public class JMSTopicListener2 {
@JmsListener(destination = JMSConfig.JMS_TOPIC_MAIL, containerFactory = "jmsListenerContainerFactory")
public void receiveTopicMessage(Email email) {
System.out.println("JMSTopicListener#2 Received <" + email + ">");
}
}
Access through web
@RestController
public class WebController {
@Autowired
JmsTemplate jmsTemplate;
@RequestMapping("/sendEmail")
public String sendEmail() {
System.out.println("Sending ************************ .");
jmsTemplate.convertAndSend(JMSConfig.JMS_TOPIC_MAIL, new Email(
"[email protected]", "Hello"));
return "Email send success!!!";
}
}
Ouput is
Sending ************************ . JMSTopicListener#2 Received
But message should be subscribed by both listener because it attached with Topic
Upvotes: 2
Views: 5348
Reputation: 3913
add to your aplication.properties
spring.jms.pub-sub-domain=true
or change bean definiton code to :
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory(
ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
// 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.
// As you said if you want to override Boot's defaults or
// values from aplication.properties you have to do it after configurer.configure()
factory.setPubSubDomain(true);
return factory;
}
UPDATE
you need to update the jmsTemplate too to use topic
@Bean
public JmsTemplate jmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory());
// jmsTemplate.setDefaultDestination(destinationTopic());;
jmsTemplate.setDefaultDestinationName(JMS_TOPIC_MAIL);
jmsTemplate.setConnectionFactory(connectionFactory());
jmsTemplate.setMessageConverter(jacksonJmsMessageConverter());
jmsTemplate.setPubSubDomain(true);
return jmsTemplate;
}
OR
@RestController
public class WebController {
@Autowired
JmsTemplate jmsTemplate;
@Autowired
ActiveMQTopic destinationTopic;
@RequestMapping("/sendEmail")
public String sendEmail() {
System.out.println("Sending ************************ .");
jmsTemplate.convertAndSend(destinationTopic, new Email(
"[email protected]", "Hello"));
return "Email send success!!!";
}
}
Upvotes: 7