A Spring Boot sample app (and learning exercise!) that integrates RabbitMQ using Spring AMQP.
It could be used as boilerplate for developing microservices that produce and consume AMQP messages.
AMQP is an open standard wire specification for asynchronous message communication. AMQP is a platform-neutral binary protocol standard - libraries can be written in different programming languages and run on different environments.
AMQP is made up of exchanges, queues, and bindings. Clients publish a message to an AMQP exchange with a routing key. Queues are bound to an exchange using a routing key. The exchange then distributes the messages to the interested queues.
This sample app will demonstrate how to use and test 3 different exchange types:
- Direct Exchange – routes messages to a queue by matching a complete routing key.
- Fanout Exchange – routes messages to all the queues bound to it.
- Topic Exchange – routes messages to multiple queues by matching a routing key to a pattern.
The fastest way to get up and running is to use the Docker image:
docker pull rabbitmq;
docker run -d -p 5672:5672 -p 15672:15672 --name my-rabbit rabbitmq:3-management
Once it's up and running, you can access the management UI using: http://localhost:15672
The default login credentials are guest/guest
The alternative is to install it (and Erlang) natively as per the official guide.
You'll need JDK 11 installed on your dev box.
You can use Gradle or Maven to build the app.
Both Gradle Wrapper and Maven Wrapper are included in the project.
- From the project root, run
./gradlew build
- To generate the Javadoc, run
./gradlew javadoc
and look in the./build/docs/javadoc
folder.
- From the project root, run
./mvnw clean install
- Take a look at the Javadoc in the
./target/apidocs
folders after the build completes.
The app uses the Google Style Guide which is enforced during both the Gradle and Maven build - see the build.gradle and pom.xml files respectively. The Checkstyle report locations are:
- Gradle -
./build/reports/checkstyle/main.html
- Maven -
./target/checkstyle-result.xml
Code coverage is provided by JaCoCo and is enforced at build time. It's currently set to 80% line coverage. See the build files. The coverage report locations are:
- Gradle -
./build/report/jacoco/test/html/index.html
- Maven -
./target/jacoco-report/index.html
SpotBugs is run at build time. Any bugs found will fail the build. The bug report locations are:
- Gradle -
./build/report/jacoco/test/html/index.html
- Maven -
./target/spotbugsXml.xml
Unit tests are run as part of both Gradle and Maven builds.
JUnit 4 and Mockito is used to unit test the code.
The unit test report locations are:
- Gradle -
build/reports/tests/test/index.html
- Maven -
./target/surefire-reports
The integration tests require a running instance of Rabbit - Testcontainers is used to achieve this. You'll need to stop any other instance of Rabbit that you have running, otherwise the tests will fail to due to port clashes.
The IT tests are located here.
The Spring profile must be set to 'integration-test' in the ./config/application.properties file:
spring.profiles.active=integration-test
To run the IT tests:
- Gradle -
./gradlew integrationTests
- Maven
./mvnw clean install -Pint
The IT report locations are:
- Gradle -
./build/reports/tests/integrationTests/index.html
- Maven -
./target/failsafe-reports
The configuration is held in the ./config/application.properties file.
# Connection Factory details.
amqp.connection.hostname=localhost
amqp.connection.port=5672
amqp.connection.username=guest
amqp.connection.password=guest
# Set to false to stop error messages going back onto head of queue and looping forever!
spring.rabbitmq.listener.simple.default-requeue-rejected=false
# Uncomment for the appropriate ErrorHandlingApp demo being run.
# The Rabbit Docker container will need to be restarted after each change to remove the queues.
amqp.configuration.current=simple-dlq
#amqp.configuration.current=custom-dlx
#amqp.configuration.current=parking-lot-dlx
If the amqp.connection.*
properties are not set, Spring AMQP will use defaults: $hostname, 5672 and
guest/guest for credentials.
More details on the amqp.configuration.*
properties can be found in the
User Guide section below.
There are 5 demos:
- A simple "Hello World!" app.
- A publish messages example using Direct, Fanout, and Topic exchanges.
- Error Handling using a simple Dead Letter Queue (DLQ).
- Error handling using a custom Dead Lead Exchange (DLX).
- Error handling using a Parking Lot Queue.
You'll need to restart the Rabbit Docker container after running each demo app in order to remove the queues.
docker container restart CONTAINER_ID
You can view the exchanges, queues, and messages in the Rabbit UI: http://localhost:15672
The Hello World! app is the most basic example of a Spring Boot app using Spring AMQP - a good place to start.
From the the app from the project root folder using:
- Gradle -
./gradlew bootRun
- Maven -
./mvnw spring-boot:run
The Publish Message app will publish a message to a Direct, Fanout, and Topic Exchange. Message consumers will read the message off the appropriate queue and log its contents.
From the project root folder using:
- Gradle -
./gradlew bootRun -PmainClass=com.gazbert.rabbitsample.publish.PublishMessageApp
- Maven -
./mvnw spring-boot:run -Dstart-class=com.gazbert.rabbitsample.publish.PublishMessageApp
The Error Handling app can be run using 3 different configurations:
- Simple DLQ - a message is published to a Direct exchange. The Consumer reads the message off the queue and then throws a business exception. This exception is then routed to a DLQ where a Consumer reads the failed message and logs it.
- Custom DLX - a business exception is thrown as in the previous example and sent to a DLQ. This time, the Consumer attempts to re-send the message 3 times before giving up and discarding it.
- Parking Lot - as in the previous example, the failed message is re-sent 3 times, but instead of discarding it, the Consumer places the failed message on the Parking Lot Queue for manual investigation.
You'll need to update the ./config/application.properties file
and set the amqp.configuration.current
property to the example you want to run:
# Valid values are: simple-dlq, custom-dlx, parking-lot-dlx
amqp.configuration.current=simple-dlq
Run the app from the project root folder using:
- Gradle -
./gradlew bootRun -PmainClass=com.gazbert.rabbitsample.errorhandling.ErrorHandlingApp
- Maven -
./mvnw spring-boot:run -Dstart-class=com.gazbert.rabbitsample.errorhandling.ErrorHandlingApp
Logging for the app is provided by log4j.
The log file is written to logs/app.log
using a rolling policy. When a log file size reaches
100 MB or a new day is started, it is archived and a new log file is created.
The app will create up to 7 archives on the same day; these are stored in a directory based on the current year and month. Only the last 90 archives are kept. Each archive is compressed using gzip.
The logging level is set at info
. You can change this default logging configuration in
the config/log4j2.xml
file.
Issues and new features are managed using the project Issue Tracker - submit bugs here.
You are welcome to take on new features or fix bugs! See here for how to get involved.
This sample app is based off the excellent Spring AMQP tutorials by Baeldung.
- The Spring AMQP documentation.
- Routing Topologies and best practice.
- The official Spring AMQP Sample apps.