Architecture & DesignGetting Started with JMS in Spring

Getting Started with JMS in Spring

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Spring JMS can be used effectively to establish communication between applications. A message-oriented middle ware, typically referred to as MQ Server, can be developed to establish the communication. The primary benefit of a message queue or MQ Server is that it enables a loosely coupled asynchronous application integration. This article provides an overview of JMS in Spring and its implementation using appropriate examples.

An Overview

Messaging typically means an exchange of data bytes between two parties. In a distributed environment, it refers to the communication between loosely coupled applications of system components. It is this decoupled nature of JMS that makes it significantly different from other system of communication, such as TCP sockets, RMI, or CORBA. The decoupled nature also leverages JMS to easily integrate disparate platforms and architectures. This enhances both scalability and reliability of message delivery without creating any bottlenecks.

JMS is an implementation of Java Message Oriented Middleware (MOM) and is the DeFacto standard for sending and receiving messages in an MQ (Message Queue) Server. An MQ Server acts as a middle man between the message sender and receiver; this is done with the help of message queues. Suppose, in a disparate system, the applications that are running in different machines need to communicate/ What options do we have? Of course, we can use SOAP or REST Web services, but do we have any other option to explore?. Web services are a viable option, no doubt, but in many circumstances, it may not be available or even down. In such a case, we can use JMS and put our message in a message queue by implementing a MQ Server. The application that wants to send a message hands over the message to the MQ transport. It then immediately writes the message to the disk before acknowledging any receipt to the sender. During the message exchange, the protocol ensures that the message is delivered and no message is lost.

JMS message exchange sequence
Figure 1: JMS message exchange sequence

Messaging Techniques

There are two major type of messaging model: point-to-point and publisher-subscriber. The MQ Server keeps a list of queues and topics which adhere to these two models, respectively. In both, the model MQ Server enables the application to connect to and to send and receive messages.

The queue adheres to the point-to-point message exchange model. When a producer sends a message, it is put in the queue maintained by the server. The message is delivered to the one that immediately connects as the next consumer. The senders and receivers are predefined and static.

The topic, on the other hand, is an implementation of the publisher-subscriber messaging model. The idea here is more versatile in the sense that any number of clients can subscribe to the message within a topic. Therefore, when a message of a particular topic is published, it is delivered to all the clients who have subscribed to that topic. This technique is more dynamic in the sense that the designated publisher subscriber role can be altered at run time.

JMS Components

The key components of JMS are as follows:

  • JMS Provider: It is a MOM implementation that provide message broker service. Additionally, it also provides other functionalities required for administrative and control purposes, necessary for a fully featured messaging product (ActiveMQ, IBM MQ, and so forth).
  • JMS Client: JMS client is the application that receives and sends messages.
  • JMS Producer or Publisher: It signifies two types of JMS client that sends messages either using message queue or topic, as discussed above.
  • JMS Consumer or Subscriber: It signifies two types of JMS client that receives messages either using a message queue or topic, as discussed above.
  • JMS Application: A JMS application that hosts one JMS provider and many JMS clients.

ActiveMQ Server

There are many MQ Server implementation available, such as IBM MQ, RabbitMQ, Apache ActiveMQ, and so on. Here, we’ll mainly focus on ActiveMQ because it is popular, open source, free, and written in Java. ActiveMQ supports many cross-language clients and protocols such as C, C++, C#, Ruby, Perl, Python, PHP, and, of course, Java. ActiveMQ can easily be embedded into Spring Application and the Spring BOOT support provides a ready starter for it.

How Does It Work?

A producer connects to the MQ Server and starts sending messages to either the queue or topic. A consumer connects to the server and starts receiving messages from the queue or the topic of interest. From the point of view of using the APIs, they are all the same. Since JMS 1.1, the API has been unified in a manner that there is no difference in dealing with queue or topic separately.

Using Spring JMS

The key to core JMS support in Spring is the JmsTemplate class. It handles the intricacies of sending and receiving messages between clients.

Messaging Techniques

There are two major type of messaging model: point-to-point and publisher-subscriber. The MQ Server keeps a list of queues and topics which adhere to these two models, respectively. In both, the model MQ Server enables the application to connect to and to send and receive messages.

The queue adheres to the point-to-point message exchange model. When a producer sends a message, it is put in the queue maintained by the server. The message is delivered to the one that immediately connects as the next consumer. The senders and receivers are predefined and static.

The topic, on the other hand is an implementation of the publisher-subscriber messaging model. The idea here is more versatile in the sense that any number of clients can subscribe to the message within a topic. Therefore, when a message of a particular topic is published, it is delivered to all the clients who have subscribed to that topic. This technique is more dynamic in the sense that designated publisher subscriber role can be altered at run time.

JMS Components

The key components of JMS are as follows:

  • JMS Provider: It is a MOM implementation that provide message broker service. Additionally, it also provides other functionalities required for administrative and control purposes, necessary for a fully featured messaging product (ActiveMQ, IBM MQ, and the like)
  • JMS Client: JMS client is the application that receives and sends messages.
  • JMS Producer or Publisher: It signifies two types of JMS client that sends messages either using a message queue or topic, as discussed above.
  • JMS Consumer or Subscriber: It signifies two types of JMS client that receives messages either using a message queue or topic, as discussed above.
  • JMS Application: A JMS application hosts one JMS provider and many JMS clients.

ActiveMQ Server

There are many MQ Server implementations available, such as IBM MQ, RabbitMQ, Apache ActiveMQ, and so forth. Here, we’ll focus mainly on the ActiveMQ because it is popular, open source, free, and written in Java. ActiveMQ supports many cross-language clients and protocols such as C, C++, C#, Ruby, Perl, Python, PHP, and, of course, Java. The ActiveMQ can easily be embedded into Spring Application and the Spring BOOT support provides a ready starter for it.

How Does It Work?

A producer connects to the framework not explicitly specified. JmsTemplate uses point-to-point queues for message operation by default. According to the Spring Framework Reference, the JMS API provides two types of send methods:

  • One that takes delivery mode, priority, and time-to-live as Quality of Service (QoS) parameters and
  • One that takes no QOS parameters, which uses default values.

Because there are many send methods in JmsTemplate, the setting of the QoS parameters has been exposed as bean properties to avoid duplication in the number of send methods. Similarly, the timeout value for synchronous receive calls is set by using the setReceiveTimeout property.

To function, JmsTemplate requires a reference to ConnectionFactory. As a part of the JMS specification, it serves as an entry point for JMS. The client uses it to connect with the JMS provider. The connection factory provides several generic and some vendor-specific parameters that may be set by using an XML configuration file or by using annotation.

Note that in the following example, we have used only the default parameters. However, they may be overridden and set up appropriately according to the requirement.

A Quick Example

This is a rudimentary implementation to keep it simple and illustrate the idea in code. The code also is available in GitHub.

<?xml version="1.0" encoding="UTF-8"?>
<project 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
      http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.mano.jmsapp</groupId>
   <artifactId>jms-app</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>jms-app</name>
   <description>Demo project for Spring Boot</description>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>
         spring-boot-starter-parent
      </artifactId>
      <version>2.0.4.RELEASE</version>
      <relativePath/>
         <!-- look up parent from repository -->
   </parent>
   <properties>
      <project.build.sourceEncoding>
         UTF-8
      </project.build.sourceEncoding>
      <project.reporting.outputEncoding>
         UTF-8
      </project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>
            spring-boot-starter-activemq
         </artifactId>
      </dependency>
      <dependency>
         <groupId>org.apache.activemq</groupId>
         <artifactId>
            activemq-broker
         </artifactId>
      </dependency>
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>
            jackson-databind
         </artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>
            spring-boot-starter-test
         </artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>
               spring-boot-maven-plugin
            </artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Listing 1: pom.xml

package com.mano.jmsapp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MessageSender {
   @Autowired
   private JmsTemplate jmsTemplate;
   public void send(final String queue,
         final String msg){
      jmsTemplate.convertAndSend(queue, msg);
   }
}

Listing 2: MessageSender.java

package com.mano.jmsapp;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiver {
   @JmsListener(destination = "msgQueue",
      containerFactory = "jmsListenerContainerFactory")
   public void receiveMessage(String msg) {
      System.out.println("Message Receivednn");
      System.out.println("Message received from
         Queue: "+msg);
   }
}

Listing 3: MessageReceiver.java

package com.mano.jmsapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure
   .SpringBootApplication;
import org.springframework.boot.autoconfigure.jms.
   DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context
   .ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config
   .DefaultJmsListenerContainerFactory;
import org.springframework.jms.config
   .JmsListenerContainerFactory;
import javax.jms.ConnectionFactory;
@SpringBootApplication
@EnableJms
public class JmsApplication {
   @Bean
   public JmsListenerContainerFactory<?>
         jmsListenerContainerFactory
         (ConnectionFactory connectionFactory,
          DefaultJmsListenerContainerFactoryConfigurer
            configurer) {
      DefaultJmsListenerContainerFactory factory =
         new DefaultJmsListenerContainerFactory();
      configurer.configure(factory, connectionFactory);
      return factory;
   }

   public static void main(String[] args) throws
         Exception{
      ConfigurableApplicationContext context =
         SpringApplication.run(JmsApplication.class,
         args);
      MessageSender sender=context.getBean("messageSender",
         MessageSender.class);
      sender.send("msgQueue","Hi! How are you?");
      context.close();
   }
}

Listing 4: JmsApplication.java

Output

//localhost started
2018-09-14 12:31:12.463  INFO 8091 --- [     main]
   o.a.activemq.broker.TransportConnector   : Connector vm:
2018-09-14 12:31:12.548  INFO 8091 --- [     main]
   c.mano.jmsapp.jmsapp.JmsAppApplication   :
   Started JmsAppApplication in 2.907 seconds
   (JVM running for 3.628)
Message Received

Message received from Queue: Hi! How are you?

2018-09-14 12:31:12.635  INFO 8091 --- [     main]
   s.c.a.AnnotationConfigApplicationContext : Closing
   org.springframework.context.annotation
   .AnnotationConfigApplicationContext@5d47c63f: startup date
   [Fri Sep 14 12:31:10 IST 2018]; root of context hierarchy
2018-09-14 12:31:12.638  INFO 8091 --- [     main]
   o.s.c.support.DefaultLifecycleProcessor  : Stopping beans
   in phase 2147483647

Conclusion

This article gave you an idea about JMS in Spring, available components, MOM services, and its providers. Also, we have implemented the API using Spring Boot and a simple example. The idea can be extended to implement a more complex application that uses JMS and other Spring features.

References

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories