JMS and AMQP in RabbitMQ

You’ve seen Java Message Service (JMS) and Advanced Message Queueing Protocol (AMQP) mentioned in the context of enterprise messaging — But what are they? Are they related? And what’s their connection to RabbitMQ?

Lots of questions, but let’s start with the first one: What are they?

Both JMS and AMQP enable message-based communication in different contexts— JMS is tailored for Java applications, providing a standardized way for Java programs to communicate asynchronously. AMQP, on the other hand, is an open standard protocol that supports cross-platform messaging, making it ideal for connecting systems written in different programming languages and/or running on different operating systems.

That was just an overview, now, let’s peel the layers back…

Java Message Service(JMS)

The JMS specification originates and is still heavily used in the Java ecosystem - Why?

Building distributed Java applications (and distributed applications in general) has several benefits but they are relatively more complex to build. For example, how do you coordinate and get the services to communicate?

In distributed architectures, services often communicate asynchronously via lightweight messaging, a practice that holds in the Java ecosystem. Previously, Java applications used different messaging systems, each with its own API, making it hard to switch between them— a standardized way to handle messaging was needed— enter JMS.

JMS, specifically designed for Java applications, defines a set of high-level APIs that these applications use to communicate with each other via messages.

By providing a common interface, JMS aims to standardize messaging between applications in the Java ecosystem. This makes it easy to replace any JMS-based message broker or client library with another one, provided both brokers support the underlying protocol used for communication.

JMS architecture

Working with JMS is pretty straightforward. Client applications called producers would publish messages to a destination on a JMS provider or broker. Other client applications called consumers would subscribe to a destination and receive messages from the broker.

JMS is just an API, meaning it provides a standard set of commands for sending and receiving messages but does not handle the actual transport of the messages. When Producers and Consumers connect to a JMS broker, the API hides the details of the underlying communication protocol used to transmit messages.

The underlying communication protocol used to transmit messages to a JMS broker/provider varies from broker to broker . For instance, ActiveMQ supports a range of protocols such as OpenWire, STOMP, XMPP, MQTT, WSIF, AMQP, and even REST (over HTTP).

The flaws of JMS

While JMS unarguably standardizes messaging within the Java ecosystem, it gets a bit tricky when a non-JMS client needs to connect to a JMS broker — Picture this scenario:

On one end you have a producer written in Java, publishing messages to ActiveMQ via JMS over the OpenWire protocol. On the other end, you have a consumer written in Python consuming messages from ActiveMQ over the STOMP protocol.

In the illustration above, the Java Producer uses the ActiveMQ JMS client to communicate with the broker via JMS over OpenWire. The Python Consumer uses the PyActiveMQ client to talk to the broker over STOMP — Since it’s impossible to have a JMS-based Python client.

For this cross-platform scenario to be implemented with a JMS-centric broker, the broker has to provide a message bridge that can parse the OpenWire packets to STOMP packets. Thus, you cannot easily replace one broker with any other, as the new broker should also support the transformations that the existing broker was supporting.

The scenario above illustrates that JMS isn’t the right solution for cross-platform interoperability. While this is doable, it is not the easiest thing to do.

This is exactly why AMQP was created; to standardize cross-platform messaging interoperability. Let’s talk about it.

Advanced Message Queueing Protocol (AMQP)

From the outset, AMQP was intended to be an open standard created to standardize cross-platform messaging interoperability. By being open, any vendor could implement the AMQP standard in their broker and client libraries could be built in any programming language and by anyone.

Essentially, whereas JMS is Java-focused, AMQP provides a specification for an industry-standard wire-level messaging protocol. Consequently, any client that implements the protocol, can talk to any broker that also implements the AMQP protocol.

Messaging clients using AMQP are completely agnostic to the AMQP message broker being used. The same goes for the AMQP-based message brokers — They allow clients written in any programming language and running on any operating system to connect to them.

Cycling back to the previous scenario we considered — On one end, you could have an AMQP-based Java client library publishing messages to an AMQP-based message broker like RabbitMQ. Then on the other end, you could also have an AMQP-based Python client library consuming messages from the AMQP broker.

With AMQP, the broker does not have to provide a message bridge for some protocol transformation — think interoperability.

AMQP architecture

With an AMQP message broker, typically:

  • A service publishes messages to the message broker.
  • The messages published go to an exchange first, then to a queue. Think of an exchange as the entry point into the message broker, whose job is to route the message from the producer into the correct queue.
  • Exchanges route messages to queues with the help of bindings, which are rules that define the relationship between an exchange and a queue. So when the exchange receives a message It looks at that message’s properties and then routes it to the correct queue.
  • A message typically has a routing key, which indicates what queue it is supposed to land in.
  • That message is then stored in a queue until it is consumed.
  • That is done by the consuming service, where a consumer subscribes to a queue and receives messages from it. Once a message is consumed, it's removed from the queue.

This binding mechanism, combined with various exchange types, allows for complex routing logic in AMQP which, in turn, opens up doors for various messaging use cases like publish/subscribe, point-to-point, and request/reply patterns in AMQP.

Now that we know what JMS and AMQP are, let’s take our exploration a step further.

JMS & AMQP: Are they related?

JMS and AMQP are related to an extent since they are both used to enable message-based communication between different parts of a system, but that’s where the similarities end.

JMS and AMQP have distinct roles and features. While JMS is simply a Java API specification, AMQP is a protocol that defines how messages are formatted and transmitted across the network, allowing for interoperability between systems written in different programming languages.

The core difference lies in their scope and usage: JMS is specific to the Java ecosystem, making it ideal for enterprise Java applications, while AMQP is language-agnostic and designed for broader interoperability and cross-platform messaging.

The title of this blog says “JMS & AMQP in RabbitMQ”, but we haven’t said a thing about RabbitMQ so far — Now, let’s go in that direction.

JMS & AMQP: The connection to RabbitMQ

For those new to it, RabbitMQ is simply a popular open-source message broker. A message broker inherently enables different applications and systems to communicate with each other using messages.

Using JMS with RabbitMQ

RabbitMQ supports the Java Message Service (JMS) API, allowing JMS-based Java applications to use RabbitMQ as a messaging broker. To use JMS with RabbitMQ, you will need to do the following:

  • Enable the RabbitMQ JMS topic selector plugin: This plugin is included in RabbitMQ versions ≥ 3.6.3
    rabbitmq-plugins enable rabbitmq_jms_topic_exchange
    You don’t need to restart the broker to activate the plugin.
  • Install the JMS client for RabbitMQ and its dependencies: Use your favourite build management tool to add the client dependencies to your project.
  • You can then connect to RabbitMQ and publish or consume messages in your producer and consumer respectively

When Java developers use JMS with RabbitMQ, they can leverage the familiar JMS API to handle messaging tasks such as sending, receiving, and processing messages asynchronously. This makes it easier to integrate RabbitMQ into existing Java-based systems that already use JMS.

Using AMQP with RabbitMQ

RabbitMQ is natively built on the Advanced Message Queuing Protocol (AMQP). Consequently, using AMQP with RabbitMQ is straightforward.

You simply need an AMQP client library that is available across different platforms and programming languages.

This makes RabbitMQ an excellent choice for systems that require cross-language interoperability.

Conclusion

RabbitMQ supports both JMS and AMQP. This means Java applications can use RabbitMQ with the familiar JMS API, while other systems can leverage AMQP for reliable and interoperable messaging.

Feel free to create a RabbitMQ instance on CloudAMQP and try out JMS.

CloudAMQP - industry leading RabbitMQ as a service

Start your managed cluster today. CloudAMQP is 100% free to try.

13,000+ users including these smart companies