RabbitMQ ist als Messaging-System Teil der vFabric Cloud Application Platform. Die Unterstützung des performanten Messaging Protokolls AMQP prädestiniert RabbitMQ für den Einsatz in Hochverfügbarkeitsszenarien. RabbitMQ ist ein Open-Source-Produkt und kann daher auch außerhalb der vFabric Plattform eingesetzt werden. Kommerzieller Support steht bei Bedarf zur Verfügung.
In diesem Artikel soll gezeigt werden, wie Sie mit Hilfe von Spring AMQP einen RabbitMQ-Broker an Ihre Java-Anwendung anbinden können.
Erlang/OTP Installation
RabbitMQ ist in Erlang implementiert. Da Erlang auf einer eigenen Runtime ausgeführt wird, müssen wir zunächst die Erlang-Runtime OTP (Open Telecom Platform) installieren. Wir verwenden den Release R14B02 für die Windows-Plattform. Als Installationsverzeichnis wählen wir C:\erl5.8.3 und definieren eine Umgebungsvariable, die auf dieses Verzeichnis zeigt:
1ERLANG_HOME=C:\erl5.8.3
RabbitMQ Installation
Nach dem Download von RabbitMQ entpacken wir das ZIP nach C:\rabbitmq_server-2.4.1. Gestartet wird RabbitMQ durch den Aufruf des Skripts
1C:\rabbitmq_server-2.4.1\sbin\rabbitmq-server.bat
RabbitMQ Server
RabbitMQ zeichnet sich durch einen geringen initialen Speicherverbrauch aus und ist schnell hochgefahren, was in elastisch skalierenden Cloud-Umgebungen von Vorteil ist. Client-APIs werden für verschiedene Sprachen angeboten, u.a. gibt es APIs für Java und .NET.
Spring AMQP
Mit Spring AMQP steht ein komfortables API zur Verfügung, um auf AMQP-fähige Message-Broker zugreifen zu können. Wie üblich gibt es ein Template als zentralen Zugriffspunkt. In unserem Fall das AmqpTemplate
.
Die Abhängigkeiten zwischen den wesentlichen benötigten Spring-Projekten sind in der folgenden Abbildung dargestellt:
Spring AMQP API
Das Projekt spring-amqp
enthält im Wesentlichen allgemeine Interfaces (z.b. das AmqpTemplate
) und Schnittstellenklassen, während in spring-rabbitmq
Broker-spezifische Implementierungen liegen. spring-rabbitmq
stützt sich dabei auf die allg. Java API für RabbitMQ amqp-client
.
Ihre Client-Anwendung hängt idealerweise nur von spring-amqp
ab, so dass eine lose Kopplung entsteht und der AMQP-Broker bei Bedarf ausgetauscht werden kann.
Für die folgenden Code-Beispiele wurde diese Maven-Artefakte verwendet:
1... 2<repositories> 3 <repository> 4 <id>repository.springframework.maven.milestone</id> 5 <name>Spring Framework Maven Milestone Repository</name> 6 <url>http://maven.springframework.org/milestone</url> 7 </repository> 8</repositories> 9<properties> 10 <spring.framework.version>3.0.5.RELEASE</spring.framework.version> 11 <spring.amqp.version>1.0.0.M3</spring.amqp.version> 12 <rabbitmq.version>2.2.0</rabbitmq.version> 13</properties> 14<dependencies> 15 <dependency> 16 <groupId>org.springframework</groupId> 17 <artifactId>spring-core</artifactId> 18 <version>${spring.framework.version}</version> 19 </dependency> 20 <dependency> 21 <groupId>org.springframework.amqp</groupId> 22 <artifactId>spring-amqp</artifactId> 23 <version>${spring.amqp.version}</version> 24 <exclusions> 25 <exclusion> 26 <groupId>com.sun.jmx</groupId> 27 <artifactId>jmxri</artifactId> 28 </exclusion> 29 </exclusions> 30 </dependency> 31 <dependency> 32 <groupId>org.springframework.amqp</groupId> 33 <artifactId>spring-rabbit</artifactId> 34 <version>${spring.amqp.version}</version> 35 </dependency> 36 <dependency> 37 <groupId>org.springframework.amqp</groupId> 38 <artifactId>spring-erlang</artifactId> 39 <version>${spring.amqp.version}</version> 40 </dependency> 41 <dependency> 42 <groupId>com.rabbitmq</groupId> 43 <artifactId>amqp-client</artifactId> 44 <version>${rabbitmq.version}</version> 45 </dependency> 46 <dependency> 47 <groupId>junit</groupId> 48 <artifactId>junit</artifactId> 49 <version>4.7</version> 50 <scope>test</scope> 51 </dependency> 52 <dependency> 53 <groupId>org.springframework</groupId> 54 <artifactId>spring-test</artifactId> 55 <version>${spring.framework.version}</version> 56 <scope>test</scope> 57 </dependency> 58</dependencies> 59...
AMQP Template
Der Einfachheit halber werden die Code-Beispiele in Form eines JUnit-Tests präsentiert. Im Application Context werden eine Connection Factory und das AmqpTemplate definiert. Zusätzlich spendieren wir noch ein Bean zur Administration des Brokers.
1<!-- Connection Factory --> 2<bean id="rabbitConnFactory" 3 class="org.springframework.amqp.rabbit.connection.SingleConnectionFactory"> 4 <constructor-arg><value>localhost</value></constructor-arg> 5 <property name="username" value="guest" /> 6 <property name="password" value="guest" /> 7 <property name="virtualHost" value="/" /> 8 <property name="port" value="5672" /> 9</bean> 10 11<!-- Spring AMQP Template --> 12<bean id="template" 13 class="org.springframework.amqp.rabbit.core.RabbitTemplate"> 14 <property name="connectionFactory" ref="rabbitConnFactory" /> 15 <property name="routingKey" value="test.queue"/> 16 <property name="queue" value="test.queue"/> 17</bean> 18 19<!-- Spring AMQP Admin --> 20<bean id="admin" class="org.springframework.amqp.rabbit.core.RabbitAdmin"> 21 <constructor-arg ref="rabbitConnFactory" /> 22</bean>
Die Connection Factory wird im Wesentlichen mit den TCP/IP-Verbindungsdaten zum RabbitMQ Server versorgt. Default-Port nach einer RabbitMQ-Installation ist 5672, als Credentials können guest/guest verwendet werden.
Ein konkretes Template bezieht sich auf eine bestimmte Queue, diese trägt den Namen test.queue
.
Im folgenden Beispiel können wir guten Gewissens Autowiring verwenden, da wir genau eine Implementierung konfiguriert haben. Wir lassen uns ein AmqpAdmin
und ein AmqpTemplate
injizieren:
1@RunWith(SpringJUnit4ClassRunner.class)
2@ContextConfiguration
3public class RabbitMQClientTest {
4
5 @Autowired private AmqpAdmin admin;
6 @Autowired private AmqpTemplate template;
7
8 @Test public void simpleProducerConsumerTest() {
9 try {
10 String sent = "Catch the rabbit! " + new Date();
11 admin.declareQueue( new Queue("test.queue") );
12
13 // write message
14 template.convertAndSend( sent );
15 // read message
16 String received = (String)template.receiveAndConvert();
17
18 System.out.println( "Msg: " + received );
19 Assert.assertEquals( sent, received );
20
21 } catch (AmqpException e) {
22 Assert.fail( "Test failed: " + e.getLocalizedMessage() );
23 }
24 }
25}
Der Test verwendet zunächst den AmqpAdmin, um die gewünschte Queue test.queue
anzulegen. Diese Operation ist idempotent, d.h. sie legt eine Queue nur dann an, wenn diese noch nicht existiert.
Danach kann mit convertAndSend(...)
bequem ein beliebiges Objekt über die Leitung gesendet werden. AMQP kennt intern nur Byte-Arrays als Nachrichtentyp, daher übernimmt das Template automatisch die Konvertierung, sofern kein eigener MessageConverter konfiguriert wird. Für unser Beispiel reichen die Standard-Converter, da sowohl Producer als auch Consumer in Java sind.
Anschließend lesen wir mit receiveAndConvert(...)
synchron die nächste Nachricht aus unserer Queue und geben diese aus.
Die AmqpException
ist wie üblich eine RuntimeException, müsste also nicht direkt mit try/catch
behandelt werden, was wir als gute Tester hier aber dennoch tun.
Zusammenfassung
Wir haben gezeigt, wie wir RabbitMQ und die erforderliche Erlang-Runtime installieren und sind auf die Spring-APIs für AMQP eingegangen. Mit einem kleinen Test haben wir gezeigt, wie man als AMQP Message Producer bzw. Message Consumer agiert.
Weitere Beiträge
von Tobias Trelle
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Tobias Trelle
Software Architect
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.