In the past posts, we had learned how to consume/produce ActiveMq JMS messages. Today, JavaSampleApproach will show you way to create a SpringBoot ActiveMQ Response Management application by @SendTo
annotation.
Related posts:
– Spring ActiveMQ JMS Consumer and JMS Producer
– Send Java object messages to ActiveMQ server (specially with Bi-Directional relationship Java objects)
– Spring JMS ActiveMq Topic (Publisher-Subcribers pattern)
I. Technologies
– Java 8
– Maven 3.6.1
– Spring Tool Suite: Version 3.8.4.RELEASE
– Spring Boot: 1.5.4.RELEASE
– Apache ActiveMQ 5.14.0
II. ActiveMQ Response Management
With the Spring JMS improvements (from 4.1), we can used @SendTo
annotation to define the default next destination with @JmsListener
:
@JmsListener(destination = "${jsa.activemq.queue.listen}", containerFactory="jsaFactory") @SendTo("${jsa.activemq.queue.sendto}") public Product processOrder(Product product) { // process a newProduct return newProduct; } |
For additional headers, you could return a Message object instead:
@JmsListener(destination = "${jsa.activemq.queue.listen}", containerFactory="jsaFactory") @SendTo("${jsa.activemq.queue.sendto}") public Message<Product> receive(Product product, @Header("company") String companyName){ ... Message<Product> mesage = MessageBuilder .withPayload(product) .setHeader("type", product.getType()) .build(); return mesage; } |
@JmsListener
methods, we can also place the @SendTo
annotation at the class level to share a default reply destination.III. Practice
In the tutorial, we create 2 SpringBoot projects {SpringActiveMqProducerConsumer, SpringActiveMqSendTo}:
Step to do:
– Create SpringBoot projects
– Create model messages
– Configure ActiveMq ConnectionFactory
– Create Jms Producer/Listeners
– Run and check results
1. Create SpringBoot projects
Using SpringToolSuite, create 2 projects SpringBoot projects {SpringActiveMqProducerConsumer, SpringActiveMqSendTo}, then add dependencies:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> |
2. Create model messages
Create 2 model classes {Company
, Product
}:
– Company:
package com.javasampleapproach.activemq.model; import java.util.List; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id", scope = Company.class) public class Company { private String name; private List<Product> products; public Company(){ } public Company(String name){ this.name = name; } public Company(String name, List<Product> products){ this.name = name; this.products = products; } // name public String getName() { return name; } public void setName(String name) { this.name = name; } // products public void setProducts(List<Product> products){ this.products = products; } public List<Product> getProducts(){ return this.products; } } |
– Product:
package com.javasampleapproach.activemq.model; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id", scope = Product.class) public class Product { private String name; private String type; private Company company; public Product(){ } public Product(String name, String type){ this.name = name; this.type = type; } public Product(String name, Company company){ this.name = name; this.company = company; } // name public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType(){ return this.type; } public void setType(String type){ this.type = type; } // products public void setCompany(Company company){ this.company = company; } public Company getCompany(){ return this.company; } @Override public String toString() { String info = String.format("[name = %s, type = %s]", this.name, this.type); return info; } } |
3. Configure ActiveMq ConnectionFactory
– Create ActiveMqConnectionFactoryConfig
file:
package com.javasampleapproach.activemq.config; import javax.jms.ConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.config.JmsListenerContainerFactory; 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; @Configuration public class ActiveMqConnectionFactoryConfig { @Value("${jsa.activemq.broker.url}") String brokerUrl; @Value("${jsa.activemq.borker.username}") String userName; @Value("${jsa.activemq.borker.password}") String password; /* * Initial ConnectionFactory */ @Bean public ConnectionFactory connectionFactory(){ ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); connectionFactory.setBrokerURL(brokerUrl); connectionFactory.setUserName(userName); connectionFactory.setPassword(password); return connectionFactory; } @Bean // Serialize message content to json using TextMessage public MessageConverter jacksonJmsMessageConverter() { MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); converter.setTargetType(MessageType.TEXT); converter.setTypeIdPropertyName("_type"); return converter; } /* * Used for Receiving Message */ @Bean public JmsListenerContainerFactory<?> jsaFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setMessageConverter(jacksonJmsMessageConverter()); configurer.configure(factory, connectionFactory); return factory; } /* * Used for Sending Messages. */ @Bean public JmsTemplate jmsTemplate(){ JmsTemplate template = new JmsTemplate(); template.setMessageConverter(jacksonJmsMessageConverter()); template.setConnectionFactory(connectionFactory()); return template; } } |
4. Create Jms Producer/Listeners
4.1 For SpringActiveMqProducerConsumer project
– Create a Producer:
import javax.jms.JMSException; import javax.jms.Message; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessagePostProcessor; import org.springframework.stereotype.Component; import com.javasampleapproach.activemq.model.Product; @Component public class JmsProducer { @Autowired JmsTemplate jmsTemplate; @Value("${jsa.activemq.queue.producer}") String queue; public void send(Product product, String companyName){ jmsTemplate.convertAndSend(queue, product, new MessagePostProcessor() { public Message postProcessMessage(Message message) throws JMSException { message.setStringProperty("company", companyName); return message; } }); } } |
– Create a Consumer:
package com.javasampleapproach.activemq.jms.consumer; import org.springframework.jms.annotation.JmsListener; import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; import com.javasampleapproach.activemq.model.Product; @Component public class JmsConsumer { @JmsListener(destination = "${jsa.activemq.queue.consumer}", containerFactory="jsaFactory") public void appleReceive(Product product, @Header("type") String productType){ if("iphone".equals(productType)){ System.out.println("Recieved Iphone: " + product); }else if("ipad".equals(productType)){ System.out.println("Recieved Ipad: " + product); } } } |
4.2 For SpringActiveMqSendTo project
– Create a JmsReplyConsumer:
package com.javasampleapproach.activemq.jms.consumer; import org.springframework.jms.annotation.JmsListener; import org.springframework.messaging.Message; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.support.MessageBuilder; import org.springframework.stereotype.Component; import com.javasampleapproach.activemq.model.Company; import com.javasampleapproach.activemq.model.Product; @Component public class JmsReplyConsumer { @JmsListener(destination = "${jsa.activemq.queue.listen}", containerFactory="jsaFactory") @SendTo("${jsa.activemq.queue.sendto}") public Message<Product> receive(Product product, @Header("company") String companyName){ // Console Log System.out.println("Recieved Message: " + product); // set company Company apple = new Company("Apple"); product.setCompany(apple); Message<Product> mesage = MessageBuilder .withPayload(product) .setHeader("type", product.getType()) .build(); return mesage; } } |
5. Run and check results
– Start ActiveMQ server with commandline: C:\apache-activemq-5.14.5>.\bin\activemq start
.
– Build and Run the SpringBoot applications {SpringActiveMqSendTo, SpringActiveMqProducerConsumer} by commandlines: {mvn install -Dmaven.test.skip=true
, mvn spring-boot:run
}
-> Logs of JmsReplyConsumer
from SpringActiveMqSendTo:
Recieved Message: [name = Iphone 7, type = iphone] Recieved Message: [name = IPadPro, type = ipad] |
-> Logs of JmsConsumer
from SpringActiveMqProducerConsumer:
Recieved Iphone: [name = Iphone 7, type = iphone, company = Apple] Recieved Ipad: [name = IPadPro, type = ipad, company = Apple] |
-> With ActiveMQ server, go to http://localhost:8161/admin/queues.jsp
: