Open source Java projects: Spring Integration

Develop a robust message-passing architecture with Spring Integration

1 2 3 4 Page 3
Page 3 of 4
  • The connectionFactory defines the connection parameters for ActiveMQ. I installed ActiveMQ and left its default configuration, which is running on my localhost and listening on port 61616.
  • The topicChannel defines a channel that will be used to publish messages (see below).
  • The outbound-channel-adapter is defined in the Spring Integration JMS namespace and it wires messages sent to the topicChannel to be published to the topic.myTopic destination, and it is configured as a topic (setting pub-sub-domain to true means that this is a topic, setting it false would make it a queue); note that the outbound-channel-adapter finds the ActiveMQ configuration via the bean with the "connectionFactory" name.
  • The listenerChannel defines a channel that will be used for consuming messages.
  • The message-driven-channel-adapter defines an adapter that listens for messages on the topic.myTopic topic and routes those to the listenerChannel.
  • The service-activator routes messages sent to the listenerChannel to the messageListenerImpl's processMessage() method.

Publish: MessageController.java

You can download the source code for this example to access all of the files. I will just review just the highlights. First, Listing 12 shows the contents of the MessageController, which is where message publishing starts.

Listing 12. MessageController.java


package com.geekcap.springintegrationexample.web;

import com.geekcap.springintegrationexample.service.PublishService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;

@Controller
public class MessageController
{
    @Autowired
    private PublishService publishService;

    @RequestMapping( value = "/message", method = RequestMethod.POST )
    @ResponseBody
    public void postMessage( @RequestBody com.geekcap.springintegrationexample.model.Message message, HttpServletResponse response )
    {
        // Publish the message
        publishService.send( message );

        // Set the status to 201 because we created a new message
        response.setStatus( HttpStatus.CREATED.value() );
    }

}
	

The MessageController is a Spring MVC controller that implements a RESTful web service that handles POSTs to the /message resource. It is expecting a JSON object, which we'll review later, and Spring MVC automatically converts that JSON into a com.geekcap.springintegrationexample.model.Message object. The MessageController has wired into it a PublishService and it invokes its send() method, passing it the Message that it received from the caller.

Listing 13 shows the the PublishServiceImpl class. (Note that the PublishService interface is not shown but can be found in the article's source code.)

Listing 13. PublishServiceImpl.java


package com.geekcap.springintegrationexample.service;

import com.geekcap.springintegrationexample.model.Message;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.stereotype.Service;

@Service
public class PublishServiceImpl implements PublishService
{
    private static final Logger logger = Logger.getLogger( PublishServiceImpl.class );

    @Autowired
    private MessageChannel topicChannel;

    @Override
    public void send( Message message )
    {
        logger.info( "Sending message to message channel: " + message );
        topicChannel.send( MessageBuilder.withPayload( message.toString() ).build() );
    }
}

The PublishServiceImpl class has wired into it the topicChannel, which we created in our application context. It sends it a String representation of the Message, using the MessageBuilder class that we looked at earlier. And that is all that is required to publish the message to the ActiveMQ topic! At this point, Spring integration uses the outbound-channel-adapter to look up the connectionFactory, find the topic.myTopic destination (as a topic), and send it the message.

Subscribe: MessageListenerImpl

On the other side of the operation, Listing 14 shows the source code for the MessageListenerImpl class (the MessageListener interface is not shown, but can be found in the source code that accompanies this article.

Listing 14. MessageListenerImpl.java


package com.geekcap.springintegrationexample.listener;

import org.apache.log4j.Logger;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Service;

@Service
public class MessageListenerImpl
{
    private static final Logger logger = Logger.getLogger( MessageListenerImpl.class );

    public void processMessage( String message )
    {
        logger.info( "Received message: " + message );
        System.out.println( "MessageListener::::::Received message: " + message );
    }
}

The MessageListenerImpl class is a service that defines a single method: processMessage(String). The message-driven-channel-adapter defined in the application context listens for messages published to the topic.myTopic topic and routes them to the listenerChannel. The service-activator routes messages sent to the listenerChannel to the messageListenerImpl's processMessage(String) method. As you can see, the MessageListenerImpl service has no idea that it is responding to JMS messages, all of the details are handled in the application context configuration.

Build and run the application

The POM file for this project is shown in Listing 15.

Listing 15. pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.geekcap</groupId>
    <artifactId>spring-integration-example</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>spring-integration-example Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>3.2.1.RELEASE</spring.version>
        <spring.integration.version>2.2.5.RELEASE</spring.integration.version>
        <servlet-api.version>2.5</servlet-api.version>
        <java.version>1.6</java.version>
        <jackson.version>1.9.12</jackson.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <!-- Spring Dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>${servlet-api.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- Spring Integration-->
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-core</artifactId>
            <version>${spring.integration.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-jms</artifactId>
            <version>${spring.integration.version}</version>
        </dependency>



        <!-- Logging: Log4J -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Include Jackson so that we can render JSON responses -->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-jaxrs</artifactId>
            <version>1.6.1</version>
        </dependency>

        <!-- Include ActiveMQ -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-core</artifactId>
            <version>5.7.0</version>
        </dependency>

        <!-- JUnit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
        <finalName>spring-integration-example</finalName>
    </build>
</project>

Application dependencies

Note that this example includes the following dependencies:

  • Core Spring
  • Spring MVC
  • Spring JMS
  • Spring Integration
  • Spring Integration JMS

You'll need to add additional dependencies based on the components that you are integrating. Some of those will have different configuration options, but they all boil down to channels and adapters.

Deploying with Tomcat and ActiveMQ

Next, use the following command to build the application:

mvn clean install

You can download Tomcat from the Apache Tomcat website. After you download it, decompress it locally and start it by executing the startup.sh or startup.bat file from the Tomcat bin directory. Copy the resultant WAR file to Tomcat's webapps directory in order to deploy it to Tomcat. You can download ActiveMQ from the Apache ActiveMQ website. After you download it, decompress it locally and start it by executing the following command from its bin directory:


./activemq start

Or, on Windows:


activemq start

Note that you can stop ActiveMQ by executing activemq stop and you can shut down Tomcat by executing shutdown.sh or shutdown.bat. I would also recommend starting ActiveMQ first so that the sample application can connect to the topic.myTopic topic and start listening for messages.

1 2 3 4 Page 3
Page 3 of 4