Skip to content

Instantly share code, notes, and snippets.

@mojavelinux
Last active September 6, 2021 03:37
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mojavelinux/6519908 to your computer and use it in GitHub Desktop.
Save mojavelinux/6519908 to your computer and use it in GitHub Desktop.
Spring Guides: Messaging with JMS

Messaging with JMS

This guide walks you through the process of publishing and subscribing to messages using a JMS broker.

What you’ll build

You’ll build an application that uses Spring’s JmsTemplate to post a single message and subscribes to it with a POJO using MessageListenerAdapter.

What you’ll need

  • About 15 minutes

  • ActiveMQ JMS broker (instructions below)

  • A favorite text editor or IDE

  • JDK 6 or later

  • Gradle 1.7+ or Maven 3.0+

  • You can also import the code from this guide as well as view the web page directly into Spring Tool Suite (STS) and work your way through it from there.

How to complete this guide

Like all Spring’s Getting Started guides, you can start from scratch and complete each step, or you can bypass basic setup steps that are already familiar to you. Either way, you end up with working code.

To start from scratch, move on to Set up the project.

To skip the basics, do the following:

  • Download and unzip the source repository for this guide, or clone it using Git:

    $ git clone https://github.com/spring-guides/gs-messaging-jms.git
  • cd into gs-messaging-jms/initial.

  • Jump ahead to Install and run ActiveMQ broker.

When you’re finished, you can check your results against the code in gs-messaging-jms/complete.

Set up the project

First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Gradle and {maven}[Maven] is included here. If you’re not familiar with either, refer to Building Java Projects with Gradle or Building Java Projects with Maven.

Create the directory structure

In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello on *nix systems:

└── src
    └── main
        └── java
            └── hello

Create a Gradle build file

Below is the initial Gradle build file. But you can also use Maven. The pom.xml file is included right here. If you are using Spring Tool Suite (STS), you can import the guide directly.

build.gradle
buildscript {
    repositories {
        maven { url "http://repo.springsource.org/libs-snapshot" }
        mavenLocal()
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'

jar {
    baseName = 'gs-messaging-jms'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
    maven { url "http://repo.springsource.org/libs-snapshot" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M2")
    compile("org.springframework:spring-jms:4.0.0.M3")
    compile("org.apache.activemq:activemq-client:5.8.0")
    testCompile("junit:junit:4.11")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.7'
}

This guide is using Spring Boot’s starter POMs.

Install and run ActiveMQ broker

To publish and subscribe to messages, you need to install a JMS broker. For this guide, you will use ActiveMQ.

Note
ActiveMQ is an AMQP broker that supports multiple protocols including JMS, the focus of this guide.

Visit the ActiveMQ download page, get the proper version, then unpack it.

Alternatively, if you use a Mac with Homebrew:

$ brew install activemq

Or on Ubuntu Linux:

$ sudo apt-get install activemq

If you download the bundle, unpack it and cd into the bin folder. If you use a package manager like apt-get or brew, it should already be on your path.

Launch a simple broker:

$ activemq start

You see output something like this:

INFO: Using default configuration
(you can configure options in one of these file: /etc/default/activemq /Users/gturnquist/.activemqrc)

INFO: Invoke the following command to create a configuration file
/usr/local/Cellar/activemq/5.8.0/libexec/bin/activemq setup [ /etc/default/activemq | /Users/gturnquist/.activemqrc ]

INFO: Using java '/Library/Java/JavaVirtualMachines/jdk1.7.0_11.jdk/Contents/Home//bin/java'
INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details
INFO: pidfile created : '/usr/local/Cellar/activemq/5.8.0/libexec/data/activemq-retina.pid' (pid '7781')
Note
To shut down the broker, run activemq stop.

Now you’re all set to run the rest of the code in this guide!

Create a message receiver

Spring provides the means to publish messages to any POJO.

src/main/java/hello/Receiver.java
package hello;

public class Receiver {
    public void receiveMessage(String message) {
        System.out.println("Received <" + message + ">");
    }
}

This is also known as a message driven POJO. As you can see in the code above, there is no need to implement any particular interface or for the method to have any particular name.

Send and receive JMS messages with Spring

Next, wire up a sender and a receiver.

src/main/java/hello/Application.java
package hello;

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.listener.SimpleMessageListenerContainer;
import org.springframework.jms.listener.adapter.MessageListenerAdapter;

@Configuration
public class Application {

    static String mailboxDestination = "mailbox-destination";

    @Bean
    ConnectionFactory connectionFactory() {
        return new CachingConnectionFactory(
                new ActiveMQConnectionFactory("tcp://localhost:61616"));
    }

    @Bean
    MessageListenerAdapter receiver() {
        return new MessageListenerAdapter(new Receiver()) {{
            setDefaultListenerMethod("receiveMessage");
        }};
    }

    @Bean
    SimpleMessageListenerContainer container(final MessageListenerAdapter messageListener,
            final ConnectionFactory connectionFactory) {
        return new SimpleMessageListenerContainer() {{
            setMessageListener(messageListener);
            setConnectionFactory(connectionFactory);
            setDestinationName(mailboxDestination);
        }};
    }

    @Bean
    JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
        return new JmsTemplate(connectionFactory);
    }

    public static void main(String args[]) throws Throwable {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(Application.class);

        MessageCreator messageCreator = new MessageCreator() {
                    @Override
                    public Message createMessage(Session session) throws JMSException {
                        return session.createTextMessage("ping!");
                    }
                };
        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
        System.out.println("Sending a new mesage.");
        jmsTemplate.send(mailboxDestination, messageCreator);

        context.close();
    }
}

The first key component is the ConnectionFactory interface. It consists of a CachingConnectionFactory wrapping an ActiveMQConnectionFactory pointed at tcp://localhost:61616, the default port of ActiveMQ.

To wrap the Receiver you coded earlier, use MessageListenerAdapter. Then use the setDefaultListenerMethod to configure which method to invoke when a message comes in. Thus you avoid implementing any JMS- or broker-specific interfaces.

The SimpleMessageListenerContainer class is an asynchronous message receiver. It uses the MessageListenerAdapter and the ConnectionFactory and is fired up when the application context starts. Another parameter is the queue name set in mailboxDestination.

Spring provides a convenient template class called JmsTemplate. JmsTemplate makes it very simple to send messages to a JMS message queue. In the main runner method, after starting things up, you create a MessageCreator and use it from jmsTemplate to send a message.

Warning
Spring’s JmsTemplate can receive messages directly through its receive method, but it only works synchronously, meaning it will block. That’s why Spring recommends that you use Spring’s SimpleMessageListenerContainer with a cache-based connection factory, so you can consume messages asynchronously and with maximum connection efficiency.

Build an executable JAR

Now that your Application class is ready, you simply instruct the build system to create a single, executable jar containing everything. This makes it easy to ship, version, and deploy the service as an application throughout the development lifecycle, across different environments, and so forth.

Below are the Gradle steps, but if you are using Maven, you can find the updated pom.xml right here and build it by typing mvn clean package.

Update your Gradle build.gradle file’s buildscript section, so that it looks like this:

buildscript {
    repositories {
        maven { url "http://repo.springsource.org/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M2")
    }
}

Further down inside build.gradle, add the following to the list of applied plugins:

apply plugin: 'spring-boot'

You can see the final version of build.gradle right here.

The Spring Boot gradle plugin collects all the jars on the classpath and builds a single ``über-jar'', which makes it more convenient to execute and transport your service. It also searches for the public static void main() method to flag as a runnable class.

Now run the following command to produce a single executable JAR file containing all necessary dependency classes and resources:

$ ./gradlew build

If you are using Gradle, you can run the JAR by typing:

$ java -jar build/libs/gs-messaging-jms-0.1.0.jar

If you are using Maven, you can run the JAR by typing:

$ java -jar target/gs-messaging-jms-0.1.0.jar
Note
The procedure above will create a runnable JAR. You can also opt to build a classic WAR file instead.

Run the service

If you are using Gradle, you can run your service at the command line this way:

$ ./gradlew clean build && java -jar build/libs/gs-messaging-jms-0.1.0.jar
Note
If you are using Maven, you can run your service by typing mvn clean package && java -jar target/gs-messaging-jms-0.1.0.jar.

When it runs, buried amidst all the logging, you should see these messages:

Sending a new mesage.
Received <ping!>

Summary

Congratulations! You’ve just developed a publisher and consumer of JMS-based messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment