- App that publishes a message using Spring AMQP's
RabbitTemplate
and subscribes to message on POJO usingMessageListenerAdapter
- Download RabbitMQ
- Or
brew install rabbitmq
(M) - Launch using default settings:
rabbitmq-server
- Launching using Docker compose:
-
docker-compose.yml
rabbitmq: image: rabbitmq:management ports: - "5672:5672" - "15672:15672"
- Run:
docker-compose up
- Run:
-
- Spring Starter Project (In STS)
- Dependencies:
- Spring for RabbitMQ
- Dependencies:
-
A Receiver to respond to published messages
-
src/main/java/com.example.messagingrabbitmq/Receiver.java
package com.example.messagingrabbitmq; import java.util.concurrent.CountDownLatch; import org.springframework.steriotype.Component; @Component public class Receiver { private CounDownLatch latch = new CountDownLatch(1); public void receiveMessage(String message) { System.out.println("Received <" + message + ">"); latch.countDown(); // Signals that message is received (not for production apps) } public CountDownLatch getLatch() { return latch; } }
-
RabbitTemplate
- Can be used to send and receive messages with RabbitMQ
- Configuration:
- Configure message listener container
- Declare queue, exchange, binding between queue and exchange
- Configure component to send messages (to test listener)
-
Automation: The following are automatically created
- Connection factory
RabbitTempalate
-
Receiver
needs to be registered with listener container (to receive messages)- Connection factory drivers both letting them to connect to RabbitMQ Server
- Sending messages
- Listener receiving messages
- Connection factory drivers both letting them to connect to RabbitMQ Server
-
Application class:
src/main/java/com.example.messagingrabbitmq/MessaginRabbitApplication.java
@SpringBootApplication public class MessagingRabbitmqApplication { static final String topicExchangeName = "spring-boot-exchange"; static final String queueName = "spring-boot"; @Bean Queue queue() { return new Queue(queueName, false); } @Bean TopicExchange exchange() { return new TopicExchange(topicExchangeName); } @Bean Binding binding(Queue queue, TopicExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with("foo.bar.#"); } @Bean SimpleMessageListenerContainer container(ConectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(queueName); container.setMessageListener(listenerAdapter); return container; } @Bean MessageListenerAdapter listenerAdapter(Receive receiver) { return new MessageListenerAdapter(receiver, "receiveMessage"); } public static main(String[] args) throws InterruptedException { SpringApplication.run(MessagingRabbitmqApplication.class, args).close(); } }
@SpringBootApplication
adds@Configuration
- Marks the class to be a source of bean definitions for application context@EnableAutoConfiguration
- Tells Boot to add beans based on- Classpath settings
- Example: If
spring-webmvc
is on classpath, the annotation flags application as web application and activates key behaviours such as setting upDispatcherServlet
- Example: If
- Other beans
- Property settings
- Classpath settings
@ComponentScan
- Tells Boot to look for components, configurations, services incom/example
package (to allow it to find controllers)
SpringApplication.run()
- Used to launch the applicationlistenerAdapter()
- The bean in the method is registered as message listener in container (container()
)- The adapter listens for messages in
spring-boot
queue MessageListenerAdapter
wrapsReceiver
since it is a POJO."receiveMessage"
- this method is invoked for receiving messages
- The adapter listens for messages in
-
CommandLineRunner
(M) is used:@Component public class Runner implements CommandLineRunner { private final RabbitTemplate rabbitTemplate; private final Receiver receiver; // @Autowired - not required anymore for constructor injection public Runner(Receiver receiver, RabbitTemplate rabbitTemplate) { this.receiver = receiver; this.rabbitTemplate = rabbitTemplate; } @Override public void run(String... args) throws Exception { System.out.println("Sending message..."); rabbitTemplate.convertAndSend(MessagingRabbitmqApplication.topicExchangeName, "foo.bar.baz", "Hello from RabbitMQ!"); receiver.getLatch().await(10000, TimeUnit.MILLISECONDS); } }
- Differences between JMS queues and AMQP queues
- Semantics:
- JMS sends queued messages to only one consumer
- AMQP queues do the same thing but AMQP producers do not send messages directly to queues
- Message is sent to exchange
- Message can then go to single queue or fan out to multiple queues
- Emulates the concept of JMS topic
- Semantics:
queue()
- generates and AMQP queueexchange()
- generates a topic exchangebinding()
- bindsqueue
andexchange
togetherQueue
,TopicExchange
andBinding
need to be defined as top-level beans for Spring AMQP to setup properlyfoo.bar.#
- Routing key- Messages sent with routing key that begins with
foo.bar.
are routed to this queue
- Messages sent with routing key that begins with
- Differences between JMS queues and AMQP queues
Runner
bean is automatically run- It retrieves
RabbitTemplate
from application context and sendsHello from RabbitMQ!
onspring-boot
queue
- It retrieves
./mvnw spring-boot:run
./mvnw clean package
java -jar target/gs-messaging-rabbitmq-0.1.0.jar