RabbitMQ is a robust and versatile message broker that can be integrated into your Micronaut applications to handle asynchronous communication. It’s especially useful for scenarios where different parts of your application need to communicate without waiting for immediate responses. In this guide, we’ll walk you through the process of integrating RabbitMQ with Micronaut.
Prerequisites
Before we dive into the integration process, make sure you have the following prerequisites in place:
- Micronaut Application: You should have a Micronaut application up and running. If you don’t have one, you can quickly create a new project using Micronaut CLI or any preferred method.
- Docker: Ensure you have a RabbitMQ server accessible or docker configured to install Rabbit MQ. You can either set up a local instance or use a cloud-based service. If not done no issue as we will setup a local rabbitMq server using Docker.
Integrating RabbitMQ in Micronaut
Follow these steps to integrate RabbitMQ with your Micronaut application:
Step 1: Run RabbitMq Application
docker run -d --name my-rabbitmq -p 5672:5672 -p 15672:15672 \
-e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest \
rabbitmq:3.11-management
This command does the following:
-d
: Runs the container in detached mode.--name my-rabbitmq
: Names the container as “my-rabbitmq.”-p 5672:5672 -p 15672:15672
: Maps the container’s ports to the host machine.-e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest
: Sets environment variables for the RabbitMQ default username and password.rabbitmq:3.11-management
: Specifies the Docker image to use, including the RabbitMQ version and the management plugin.
Step 2: Add RabbitMQ Dependency
Make sure you have the micronaut-rabbitmq
dependency in your build.gradle
or build.gradle.kts
file:
implementation("io.micronaut.rabbitmq:micronaut-rabbitmq:3.4.0")
Step 3: Configure RabbitMQ Connection
In your application.yml
or application.properties
file, configure the RabbitMQ connection details. Replace the placeholders with your RabbitMQ server information.
rabbitmq:
uri: amqp://${RABBITMQ_USER:guest}:${RABBITMQ_PASS:guest}@${RABBITMQ_HOST:localhost}:${RABBITMQ_PORT:5672}
consumer-executor: rabbit
rabbitmq
is a configuration section specifically for RabbitMQ settings within the Micronaut application.uri
is the URI (Uniform Resource Identifier) that specifies how to connect to the RabbitMQ server. It’s constructed as follows:amqp://
: This is the URI scheme for the AMQP (Advanced Message Queuing Protocol), which is the protocol used by RabbitMQ.${RABBITMQ_USER:guest}:${RABBITMQ_PASS:guest}
: This part defines the username and password for connecting to RabbitMQ. It uses environment variables for flexibility. If theRABBITMQ_USER
andRABBITMQ_PASS
environment variables are set, they will be used as the username and password. If not, the default values “guest” for both username and password are used.@${RABBITMQ_HOST:localhost}:${RABBITMQ_PORT:5672}
: This part specifies the RabbitMQ server’s hostname and port. Similarly, it uses environment variables for flexibility. IfRABBITMQ_HOST
is set, it will be used as the hostname. If not, the default value “localhost” is used. Likewise, ifRABBITMQ_PORT
is set, it will be used as the port number. If not, the default port number 5672 is used.
consumer-executor: rabbit
sets the consumer executor to “rabbit.” This likely specifies the executor that Micronaut will use for running consumers (message consumers) that process messages from RabbitMQ. In this case, it’s configured to use the “rabbit” executor.
Step 4: Create a Publisher
To send messages to RabbitMQ, we have to create Publisher for RabbitMq
package com.example.event
import io.micronaut.rabbitmq.annotation.Binding
import io.micronaut.rabbitmq.annotation.RabbitClient
@RabbitClient("rabbitmq-demo")
interface Publisher {
@Binding("event.number")
suspend fun emitEventNumber(eventNumber: Long)
}
Step 5: Create a RabbitMQ Consumer
In Micronaut, you can create RabbitMQ consumers easily by defining a method in a Micronaut bean and annotating it with @RabbitListener
. For example:
package com.example.event
import com.example.util.logger
import io.micronaut.rabbitmq.annotation.Queue
import io.micronaut.rabbitmq.annotation.RabbitListener
@RabbitListener
class Consumer {
@Queue("event-number", prefetch = 1)
fun consumeEventNumber(eventNumber: Long) {
logger().error(eventNumber.toString())
}
}
Step 6: Declare Queue and Bind to Exchange
package com.example.common
import com.rabbitmq.client.Channel
import io.micronaut.rabbitmq.connect.ChannelInitializer
import io.micronaut.runtime.event.annotation.EventListener
import io.micronaut.runtime.server.event.ServerStartupEvent
import jakarta.inject.Singleton
@Singleton
class RabbitMqBootstrap : ChannelInitializer() {
@EventListener
fun onStartupEvent(@Suppress("UNUSED_PARAMETER") event: ServerStartupEvent) {
initialize(null, "")
}
override fun initialize(channel: Channel?, name: String) {
channel?.exchangeDeclare("rabbitmq-demo", "topic", true)
channel?.queueDeclare("event-number", true, false, false, null)
channel?.queueBind("event-number", "rabbitmq-demo", "event.number", null)
}
}
Let’s break down what this code does:
- Class Definition:
RabbitMqBootstrap
is a class that extendsChannelInitializer
. This means it’s designed to initialize RabbitMQ resources related to communication channels. - Event Handling: The class defines a function called
onStartupEvent
, which is annotated with@EventListener
. This annotation indicates that this function should be triggered when a specific event occurs in the Micronaut application. In this case, it listens for theServerStartupEvent
. - Channel Initialization: The
initialize
function overrides a method from theChannelInitializer
class. It’s responsible for configuring RabbitMQ resources.- The
exchangeDeclare
method is used to declare an exchange named “rabbitmq-demo” of type “topic” with thedurable
flag set totrue
. This creates a topic exchange that is designed to route messages based on a routing key pattern. - The
queueDeclare
method declares a queue named “event-number” with various configuration options, including making itdurable
. - The
queueBind
method binds the “event-number” queue to the “rabbitmq-demo” exchange using the routing key “event.number.” This binding allows messages with the specified routing key to be routed to the queue.
- The
Step 7: Triggering the publisher
You can create a controller and initiate the publisher to publish a message. Here we have used the controller from Rest API in Micronaut
@Inject
lateinit var publisher: Publisher
@Get("/simple/{params}")
suspend fun pathVariable(params: Long): Long? {
publisher.emitEventNumber(params)
log.error("This is a test error")
return params
}
After this change, you can trigger the controller using postman or web browser
Code: Rabbit Mq Implementation in Micronaut