Spring Integration Gateway Example

0

In an enterprise world, applications communicate through messages. The message navigates from one channel to an another till it reaches its destination. At each end point of the channel you have producers and consumers, sending and receiving messages. In such scenarios, you will end up with a layer of your application making some message based calls like createMessage, channel.send() etc.

The main issue with such patterns is:

  1. If we want to replace the messaging system with some other vendor, we will have to fix all those vendor specific APIs with the new ones.
  2. The intent of the purpose is lost as instead of using domain-specific methods we are using messaging APIs

So is there a way we can decouple the application code from the messaging APIs? Gateway comes to our rescue. It encapsulates access to the messaging system from the rest of the application
Let’s see an example and we will know how it works.

Gateway Example

A gateway can be used to eliminate this coupling by creating a façade layer that abstracts away the functionality of the messaging system into a discrete interface.
Suppose we want to request customer information from some external customer maintenance system. All we need to do is first create an interface that contains the domain specific method.

CustomerService:

package com.javarticles.spring.integration.gateway;

public interface CustomerService {
    public Customer getCustomerInfo(String customerId);
}

Now in the applicationContext.xml, declare a <gateway> element with service-interface attribute set to the above interface.The other important attribute is default-request-channel. This is the request channel. There is also a default-reply-channel. You would have noticed we haven’t used it. A reply channel is optional and is not required when configuring a gateway. If there is no default-reply-channel, gateway will create a temporary point-to-point reply channel. If a publish-subscribe-channel is required, then we need to have one reply channel as to allow other interested listeners subscribed for the reply.

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
		http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:task="http://www.springframework.org/schema/task">

	<gateway id="customerService"
		service-interface="com.javarticles.spring.integration.gateway.CustomerService"
		default-request-channel="customerRequestChannel"
		default-reply-timeout="3000" />

	<channel id="customerRequestChannel" />

	<service-activator input-channel="customerRequestChannel">
		<beans:bean
			class="com.javarticles.spring.integration.gateway.CustomerServiceImpl" />
	</service-activator>
</beans:beans>
Gateway Example

Gateway Example

Customer:

package com.javarticles.spring.integration.gateway;

public class Customer {
    private String id;

    public Customer(String id) {
        super();
        this.id = id;
    }

    public String toString() {
        return "Customer: " + id;
    }
}

The request message from the gateway will be used to invoke the service adapter. Based on your need to you can use any adapter you want to service the request. The service adapter in our example will call the actual implementation to return us the customer.

CustomerServiceImpl:

package com.javarticles.spring.integration.gateway;

public class CustomerServiceImpl implements CustomerService {
    public Customer getCustomerInfo(String customerId) {
        return new Customer(customerId + ", called by: " + Thread.currentThread().getName());
    }
}

We test our Gateway example by getting the gateway bean and requesting for customer information in a loop. In the next section, we will see how to achieve this asynchronously using a task executor on the request channel.

SpringIntegrationGatewayExample:

package com.javarticles.spring.integration.gateway;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringIntegrationGatewayExample {

    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        try {
            CustomerService customerService = (CustomerService) context.getBean("customerService"); 
            System.out.println("Get Customer info synchronously");
            for (int i = 0; i < 3; i++) {
                String id = "C0" + i;
                System.out.println("Id: " + id);
                Customer customer = customerService.getCustomerInfo(id);
                System.out.println("Customer information for: " + id + "(" + customer + ")");
            }
    }
}

Output:

Get Customer info synchronously
Id: C00
Customer information for: C00(Customer: C00, called by: main)
Id: C01
Customer information for: C01(Customer: C01, called by: main)
Id: C02
Customer information for: C02(Customer: C02, called by: main)

Asynchronus Example of Gateway

To serve the request asynchronously, we use a dispatcher tag with a task-executor.

<channel id="customerRequestDispatcherChannel">
    <dispatcher task-executor="executor" />
</channel>

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
		http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:task="http://www.springframework.org/schema/task">

	<gateway id="customerService"
		service-interface="com.javarticles.spring.integration.gateway.CustomerService"
		default-request-channel="customerRequestChannel"
		default-reply-timeout="3000" />

	<channel id="customerRequestChannel" />

	<service-activator input-channel="customerRequestChannel">
		<beans:bean
			class="com.javarticles.spring.integration.gateway.CustomerServiceImpl" />
	</service-activator>

	<gateway id="customerServiceByDispatcher"
		service-interface="com.javarticles.spring.integration.gateway.CustomerService"
		default-request-channel="customerRequestDispatcherChannel"
		default-reply-timeout="3000" />

	<channel id="customerRequestDispatcherChannel">
		<dispatcher task-executor="executor" />
	</channel>

	<service-activator input-channel="customerRequestDispatcherChannel">
		<beans:bean
			class="com.javarticles.spring.integration.gateway.CustomerServiceImpl" />
	</service-activator>

	<task:executor id="executor" pool-size="5" />
</beans:beans>

SpringIntegrationGatewayExample:

package com.javarticles.spring.integration.gateway;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringIntegrationGatewayExample {

    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        try {
            CustomerService customerService = (CustomerService) context.getBean("customerService"); 
            System.out.println("Get Customer info synchronously");
            for (int i = 0; i < 3; i++) {
                String id = "C0" + i;
                System.out.println("Id: " + id);
                Customer customer = customerService.getCustomerInfo(id);
                System.out.println("Customer information for: " + id + "(" + customer + ")");
            }
            
            customerService = (CustomerService) context.getBean("customerServiceByDispatcher"); 
            System.out.println("Get Customer info asynchronously using dispatcher");
            for (int i = 0; i < 3; i++) {
                String id = "C0" + i;
                System.out.println("Id: " + id);
                Customer customer = customerService.getCustomerInfo(id);
                System.out.println("Customer information for: " + id + "(" + customer + ")");
            }
        } finally {
            context.close();
        }
    }
}

You an see the thread name as part of the customer ID just to know which thread is serving the request.

Output:

Get Customer info synchronously
Id: C00
Customer information for: C00(Customer: C00, called by: main)
Id: C01
Customer information for: C01(Customer: C01, called by: main)
Id: C02
Customer information for: C02(Customer: C02, called by: main)
Get Customer info asynchronously using dispatcher
Id: C00
Customer information for: C00(Customer: C00, called by: executor-1)
Id: C01
Customer information for: C01(Customer: C01, called by: executor-2)
Id: C02
Customer information for: C02(Customer: C02, called by: executor-3)

Download source code

This was an example about Gateway component. You can download the source code here: springintegrationGateway.zip

About Author

Ram’s expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring.
You can reach him at [email protected]

Comments are closed.