<img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=299788&amp;fmt=gif">

Easy Background Processing with Spring Integration

Software Development, Spring, Software Solutions, Java

By Joel Brinkman

There seems to be a lot of yammering these days about asynchronous servlet processing. I won’t go into the details of what it is here as there are many great write-ups on the Intertubes. While reading about asynchronous servlet processing, I found myself desperate to find an excuse to jam it into an existing project - as usual. It turns out that I have the perfect application for this technological terror.


One of our web applications allows a registered user to send an invitation to potential new users. This process begins by prompting the logged in user for the email address to which an invitation will be sent. Unfortunately, the application forces the user to wait about two seconds for the system to actually send the email before responding to the user with a confirmation that the email was sent. Only then may the user continue her work. My new invitation process will still prompt the user for an email address, but will then immediately respond to the user so that she may continue her work. Once the email is successfully sent, an unobtrusive message will be displayed asynchronously. This will truly change the world!


Ultimately our architecture is going to change from a controller that directly invokes an email sending service and then responds to the user with a confirmation page to a controller that puts a request on a Spring Integration channel, a service activator that listens for such requests and then invokes the email sending service. This new service will then respond by putting a confirmation message back on the channel where it is sent to the user via a long polling request.


The first thing we’re going to do is add Spring Integration to our project. The following dependency should cover us for now.
[html]
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
[/html]


We’re now going to configure a single channel over which we will send messages within our application. On this channel will exist a single endpoint that will handle a specific type of message dumped on the channel. In our case, this will be a message that represents the need to send an email. Let’s start by adding the channel config to the application context.


[html]
<bean id="miscPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="250" />
</bean>
<i:annotation-config/>
<i:publish-subscribe-channel id="bus" />
<i:publish-subscribe-channel id="busAsync" task-executor="miscPool" ignore-failures="true" />
<i:publish-subscribe-channel id="busSync" ignore-failures="true" />
<i:recipient-list-router id="busRouter" input-channel="bus" ignore-send-failures="true" apply-sequence="true" >
<i:recipient channel="busAsync"/>
<i:recipient channel="busSync"/>
</i:recipient-list-router>
<i:gateway id="busGateway" service-interface="com.isostech.moo.event.BusGateway"/>
[/html]


This configuration creates a threadpool in which our Spring Integration channel message handlers will execute. It also creates a general channel named “bus” and a router that dumps all bus messages onto another channel called “busAsync.” For now, it is a listener on busAsync that we are interested in creating. We can create this with a simple class and some magic annotations.


[java]
@Service
public class EmailSenderService {
@ServiceActivator(inputChannel="busAsync")
public void send(SendEmailEvent event) {
logger.info("Received request to send email.");
doSendEmailAndStuff(event);
}
}
[/java]


This service activator needs an object of the type SendEmailEvent to represent this unit of work. Such a class might look like this:

[java]
@RooJavaBean
public class SendEmailEvent {
private String emailAddress;
private String subject;
private String content;
}
[/java]


Now before we can go crazy pushing messages onto our fancy new channel, we need to define an interface for which a proxy will enable us to add messages on the channel. This is actually already referenced in our configuration as com.isostech.moo.event.BusGateway. An example of such an interface might be:

[java]
public interface BusGateway {
@Gateway(requestChannel="bus")
public void onDaBus(Object foo);
}
[/java]


Given this interface declaration, calling onDaBus() will result in the single argument being placed on the channel for processing by service activators. In our example, that would be EmailSenderService.
So, whereas our old controller may have looking like this:

[java]
public ModelAndView sendInvitation(@ModelAttribute Invitation invitation) {
emailSenderService.sendEmail(invitation); // synchronously send an email
return new ModelAndView(“someConfirmationPage”);
}
[/java]


Our new one might look like this instead:

[java]
public ModelAndView sendInvitation(@ModelAttribute Invitation invitation) {
busGateway.onDaBus(new SendEmailEvent(invitation)); // create a SendEmailEvent with an invitation and asynchronously send an email
return new ModelAndView(“someOtherPage”);
}
[/java]


While this might seem like a lot of work to go through for asynchronous emailing when a simple @Async might suffice, in our next installment, we’ll tie this with sending the client status updates over a long polling request.

TAGS: Software Development, Spring, Software Solutions, Java

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Subscribe to Our Newsletter

Recent Blog Posts