Spring Integration: A Hands-On Tutorial, Part 1
Create the domain model
We’ll need a domain object for leads, so listing 1 shows the one we’ll use. It’s not an industrial-strength representation, but it will do for the purposes of the tutorial.
Listing 1. Lead.java, a basic domain object for leads.
package crm.model;
... other imports ...
public class Lead {
private static DateFormat dateFormat = new SimpleDateFormat();
private String firstName;
private String middleInitial;
private String lastName;
private String address1;
private String address2;
... other fields ...
public Lead() { }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) {
this.firstName = firstName;
}
... other getters and setters, and a toString() method ...
}
There is nothing special happening here at all. So far the Lead class is just a bunch of getters and setters. You can see the full code listing in the download.
If you thought that was underwhelming, just wait until you see the LeadServiceImpl service bean in listing 2.
Listing 2. LeadServiceImpl.java, a dummy service bean.
package crm.service;
import java.util.logging.Logger;
import org.springframework.stereotype.Service;
import crm.model.Lead;
@Service("leadService")
public class LeadServiceImpl implements LeadService {
private static Logger log = Logger.getLogger("global");
public void createLead(Lead lead) {
log.info("Creating lead: " + lead);
}
}
This is just a dummy bean. In real life we’d save the lead to a database. The bean implements a basic LeadService interface that we've suppressed here, but it's available in the code download.
Now that we have our domain model, let’s use Spring Integration to create a service integration tier above it.
Create the service integration tier
If you look back at figure 3, you’ll see that the CRM app pushes lead data to the service bean by way of a channel called newLeadChannel. While it’s possible for the CRM app to push messages onto the channel directly, it’s generally more desirable to keep the systems you’re integrating decoupled from the underlying messaging infrastructure, such as channels. That allows you to configure service orchestrations dynamically instead of having to go into the code.
Spring Integration supports the Gateway pattern (described in the aforementioned Enterprise Integration Patterns book), which allows an application to push messages onto the message bus without knowing anything about the messaging infrastructure. Listing 3 shows how we do this.
Listing 3. LeadGateway.java, a gateway offering access to the messaging system.
package crm.integration.gateways;
import org.springframework.integration.annotation.Gateway;
import crm.model.Lead;
public interface LeadGateway {
@Gateway(requestChannel = "newLeadChannel")
void createLead(Lead lead);
}
We are of course using the Spring Integration @Gateway annotation to map the method call to the newLeadChannel, but gateway clients don’t know that. Spring Integration will use this interface to create a dynamic proxy that accepts a Lead instance, wraps it with an org.springframework.integration.core.Message, and then pushes the Message onto the newLeadChannel. The Lead instance is the Message body, or payload, and Spring Integration wraps the Lead because only Messages are allowed on the bus.
We need to wire up our message bus. Figure 4 shows how to do that with an application context configuration file.
Listing 4. /WEB-INF/applicationContext-integration.xml message bus definition.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">
<gateway id="leadGateway"
service-interface="crm.integration.gateways.LeadGateway" />
<publish-subscribe-channel id="newLeadChannel" />
<service-activator
input-channel="newLeadChannel"
ref="leadService"
method="createLead" />
</beans:beans>
The first thing to notice here is that we've made the Spring Integration namespace our default namespace instead of the standard beans namespace. The reason is that we're using this configuration file strictly for Spring Integration configuration, so we can save some keystrokes by selecting the appropriate namespace. This works pretty nicely for some of the other Spring projects as well, such as Spring Batch and Spring Security.
In this configuration we've created the three messaging components that we saw in figure 3. First, we have an incoming lead gateway to allow applications to push leads onto the bus. We simply reference the interface from listing 3; Spring Integration takes care of the dynamic proxy. Next we create a publish/subscribe ("pub-sub") channel called newLeadChannel. This is the channel that the @Gateway annotation referenced in listing 3. A pub-sub channel can publish a message to multiple endpoints simultaneously. For now we have only one subscriber—a service activator—but we already know we're going to have others, so we may as well make this a pub-sub channel.
The service activator is an endpoint that allows us to bring our LeadServiceImpl service bean onto the bus. We're injecting the newLeadChannel into the input end of the service activator. When a message appears on the newLeadChannel, the service activator will pass its Lead payload to the leadService bean's createLead() method.
Stepping back, we've almost implemented the design described by figure 3. The only part that remains is the lead creation frontend, which we'll address right now.
Create the web tier
Our user interface for creating new leads will be a web-based form that we implement using Spring Web MVC. The idea is that enrollment staff at campuses or call centers might use such an interface to handle walk-in or phone-in traffic. Listing 5 shows our simple @Controller.
Listing 5. LeadController.java, a @Controller to allow staff to create leads
package crm.web;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import crm.integration.gateways.LeadGateway;
import crm.model.Country;
import crm.model.Lead;
@Controller
public class LeadController {
@Autowired
private LeadGateway leadGateway;
@RequestMapping(value = "/lead/form.html", method = RequestMethod.GET)
public void getForm(Model model) {
model.addAttribute(Country.getCountries());
model.addAttribute(new Lead());
}
@RequestMapping(value = "/lead/form.html", method = RequestMethod.POST)
public String postForm(Lead lead) {
lead.setDateCreated(new Date());
leadGateway.createLead(lead);
return "redirect:form.html?created=true";
}
}
This isn't an industrial-strength controller as it doesn't do HTTP parameter whitelisting (for example, via an @InitBinder method) and form validation, both of which you would expect from a real implementation. But the main pieces from a Spring Integration perspective are here. We're autowiring the gateway into the @Controller, and we have methods for serving up the empty form and for processing the submitted form. The getForm() method references a Countries class that we've suppressed (it's in the code download); it just puts a list of countries on the model so the form can present a Country field to the staff member. The postForm() method invokes the createLead() method on the gateway. This will pass the Lead to the dynamic proxy LeadGateway implementation, which in turn will wrap the Lead with a Message and then place the Message on the newLeadChannel.
There are a few other configuration files you will need to put in place, including web.xml, main-servlet.xml and applicationContext.xml. There's also a JSP for the web form. As none of these relates directly to Spring Integration, we won't treat them here. Please see the code download for details.
With that, we've established a baseline system. To try it out, run
mvn jetty:run
against crm/pom.xml and point your browser at
http://localhost:8080/crm/main/lead/form.html
You should see a very basic-looking web form for entering lead information. Enter some user information (it doesn't matter what you enter—recall that we don't have any form validation) and press Submit. The console should report that LeadServiceImpl.createLead() created a lead. Congratulations!
Even though we now have a working system, it isn't very interesting. From here on out (this tutorial and the next) we'll be adding some common features to make the lead management system more capable. Our first addition will be confirmation e-mails; the next tutorial will present further additions.
| Attachment | Size |
|---|---|
| spring-integration-demo-3.zip | 18.84 KB |
| spring-integration-demo-4.zip | 21.61 KB |
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Koen VT replied on Thu, 2009/08/20 - 2:32am