Messaging in Java

Posted by Tejus Parikh on January 16, 2011

At my current employeer, we’re starting to reach the point where we need a messaging infrastructure to scale our product. The traditional Java approach is to use a JMS broker, such as ActiveMQ. However, there’s a new alternative API in the form of AMQP. Our first use-case is a fan-out queue and I took the opportunity to see how the solution would look using both API’s within Spring. You can find the code for my proof of concept on Github. I’ve only included the most relevant snippets in the post, so for a real understanding on how to configure everything, look through the source.

ActiveMQ

The heavyweight in open source Java Messaging is ActiveMQ. ActiveMQ is a traditional JMS solution. Spring provides a template class that abstracts the communication with the JMS provider. The template requires a JMS connection factory along with a destination name. The same connection factory can be used for both sending and receiving messages by classes in the same JVM. The relevant configuration bits are as follows:

    

    
This creates a destination queue, a connection factory with the host and the template for the producer. In this example, the consumer is configured as a MessageListener and therefore, does not need a template. The StatMessageConverter is a bean that converts the payload to and from JSON. I choose to send the messages as JSON since we have a multi-language infrastructure and JSON makes it easier for those diverse systems to communicate. With this configuration, sending a message with a JSON payload is as simple as:

    template.convertAndSend(message);

The consumer configuration is simpler. Since my consumer class implements MessageListener, I just need to create a listener-container and inject the bean:

    
Whenever the producer sends the message, the onMessage method of the consumer will be called by Spring.

AMQP

AMQP with Spring works much the same way. There is a template and a connection factory. However, AMQP is different than JMS. First AMQP is a wire-level protocol, whereas JMS is an API. Therefore, different AMQP implementations should be able to communicate with each other. Secondly, the paradigm is slightly different. In JMS, there is a queue and consumers and producers bind to that queue. In the AMQP world, producers talk to exchanges and consumers bind queues to those exchanges. Therefore the communication topology is fully within the configuration and is unknown to the code, making it trivial to go from a one-to-one exchange to a fan-out. The AMQP provider that made the most sense was RabbitMQ. RabbitMQ is a logical choice because it has first-party java libraries and is owned by VMWare, who also own Spring, which bodes well for the project’s future. Spring’s AMQP support requires a little more configuration compared to the JMS solution, but the basics are the same. You need connection factory, template, and a listener. The first difference is that there must be an administration bean:

  
Next the send template needs both the routing key and the exchange:

    
The statsExchange will create the exchange as part of it’s initialization. If the exchange already exists, it will bind to it. Next comes the creation of the Queue:

    
Since I want fan-out behavior, each consumer must have a unique queue name. Therefore, I use an instanceID instead of a configured property. Otherwise, the same rule for exchanges applies here, the consumers will just listen on the existing queue. The consumer is similar, but in this case we can use a regular Pojo. Since Spring’s AMQP support includes marshalling support for JSON, no special conversion needs to occur on the client side:

    
All that remains is binding the exchange to the queues:

    
Sending a message is identical to JMS:

template.convertAndSend(message);

Conclusions

This little exercise was interesting because it shows that from the programmer’s perspective, there is little difference between using AMQP or JMS. With a little care in interface design, the two solutions can be swapped with minimal development effort. For our needs, we decided to go with RabbitMQ. The solution just feels simpler for the different types of communication we need. Plus the use of an Erlang message broker feels like the right technology for the right problem.

Related Posts:

Tejus Parikh

Tejus is an software developer, now working at large companies. Find out when I write new posts on twitter, via RSS or subscribe to the newsletter: