1. Overview
Decoupling of software components is one of the most important parts of software design. One way of achieving this is using messaging systems, which provide an asynchronous way of communication between components (services). In this article, we will cover one of such systems: RabbitMQ.
RabbitMQ is a message broker that implements Advanced Message Queuing Protocol (AMQP). It provides client libraries for major programming languages.
Besides using for decoupling software components RabbitMQ can be used for:
- Performing background operations
- Performing asynchronous operation
2. Messaging Model
First, let’s have a quick, high-level look at how messaging works.
Simply put, there are two kinds of applications interacting with a messaging system: producers and consumers. Producers are those, who sends (publishes) messages to a broker, and consumers, who receive messages from the broker. Usually, this programs (software components) are running on different machines and RabbitMQ acts as a communication middleware between them.
In this article, we will discuss a simple example with two services which will communicate using RabbitMQ. One of the services will publish messages to RabbitMQ and the other one will consume.
3. Setup
For the beginning let’s run RabbitMQ using official setup guide here.
We’ll naturally use the Java client for interacting with RabbitMQ server; the Maven dependency for this client is:
<dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>4.0.0</version> </dependency>
After running the RabbitMQ broker using the official guide, we need to connect to it using java client:
ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel();
We use the ConnectionFactory to setup the connection with the server, it takes care of the protocol (AMQP) and authentication as well. Here we connect to the server on localhost, we can modify the host name by using the setHost function.
We can use setPort to set the port if the default port is not used by the RabbitMQ Server; the default port for RabbitMQ is 15672:
factory.setPort(15678);
We can set username and the password:
factory.setUsername("user1"); factory.setPassword("MyPassword");
Further, we will use this connection for publishing and consuming messages.
4. Producer
Consider a simple scenario where a web application allows users to add new products to a website. Any time when new product added, we need to send an email to customers.
First, let’s define a queue:
channel.queueDeclare("products_queue", false, false, false, null);
Each time when users add a new product, we will publish a message to a queue:
String message = "product details"; channel.basicPublish("", "products_queue", null, message.getBytes());
Lastly, we close the channel and the connection:
channel.close(); connection.close();
This message will be consumed by another service, which is responsible for sending emails to customers.
5. Consumer
Let’s see what we can implement the consumer side; we’re going to declare the same queue:
channel.queueDeclare("products_queue", false, false, false, null);
Here’s how we define the consumer that will process messages from queue asynchronously:
Consumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery( String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String message = new String(body, "UTF-8"); // process the message } }; channel.basicConsume("products_queue", true, consumer);
6. Conclusion
This simple article covered basic concepts of RabbitMQ and discussed a simple example using it.
The full implementation of this tutorial can be found in the GitHub project.