Spring Integration 4.0: A complete XML-free example

1 Introduction

Spring Integration 4.0 is finally here, and this release comes with very nice features. The one covered in this article is the possibility to configure an integration flow without using XML at all. Those people that don’t like XML will be able to develop an integration application with just using JavaConfig.
This article is divided in the following sections:
  1. Introduction.
  2. An overview of the flow.
  3. Spring configuration.
  4. Detail of the endpoints.
  5. Testing the entire flow.
  6. Conclusion.

The source code can be found at github.

The source code of the web service invoked in this example can be found at the spring-samples repository at github.

2 An overview of the flow

The example application shows how to configure several messaging and integration endpoints. The user asks for a course by specifying the course Id. The flow will invoke a web service and return the response to the user. Additionally, some type of courses will be stored to a database.

The flow is as follows:

  • An integration gateway (course service) serves as the entry to the messaging system.
  • A transformer builds the request message from the user specified course Id.
  • A web service outbound gateway sends the request to a web service and waits for a response.
  • A service activator is subscribed to the response channel in order to return the course name to the user.
  • A filter is also subscribed to the response channel. This filter will send some types of courses to a mongodb channel adapter in order to store the response to a database.

The following diagram better shows how the flow is structured:

Spring Integration 4.0 application flow diagram


3 Spring configuration

As discussed in the introduction section, the entire configuration is defined with JavaConfig. This configuration is split into three files: infrastructure, web service and database configuration. Let’s check it out:

3.1 Infrastructure configuration

This configuration file only contains the definition of message channels. The messaging endpoints (transformer, filter, etc…) are configured with annotations.


@ComponentScan("xpadro.spring.integration.endpoint")	//@Component
@IntegrationComponentScan("xpadro.spring.integration.gateway")	//@MessagingGateway
@Import({MongoDBConfiguration.class, WebServiceConfiguration.class})
public class InfrastructureConfiguration {
    @Description("Entry to the messaging system through the gateway.")
    public MessageChannel requestChannel() {
        return new DirectChannel();
    @Description("Sends request messages to the web service outbound gateway")
    public MessageChannel invocationChannel() {
        return new DirectChannel();
    @Description("Sends web service responses to both the client and a database")
    public MessageChannel responseChannel() {
        return new PublishSubscribeChannel();
    @Description("Stores non filtered messages to the database")
    public MessageChannel storeChannel() {
        return new DirectChannel();


The @ComponentScan annotation searches for @Component annotated classes, which are our defined messaging endpoints; the filter, the transformer and the service activator.

The @IntegrationComponentScan annotation searches for specific integration annotations. In our example, it will scan the entry gateway which is annotated with @MessagingGateway.

The @EnableIntegration annotation enables integration configuration. For example, method level annotations like @Transformer or @Filter.

3.2 Web service configuration

This configuration file configures the web service outbound gateway and its required marshaller.


public class WebServiceConfiguration {
    @ServiceActivator(inputChannel = "invocationChannel")
    public MessageHandler wsOutboundGateway() {
        MarshallingWebServiceOutboundGateway gw = new MarshallingWebServiceOutboundGateway("http://localhost:8080/spring-ws-courses/courses", jaxb2Marshaller());
        return gw;
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        return marshaller;


The gateway allows us to define its output channel but not the input channel. We need to annotate the adapter with @ServiceActivator in order to subscribe it to the invocation channel and avoid having to autowire it in the message channel bean definition.

3.3 Database configuration

This configuration file defines all necessary beans to set up mongoDB. It also defines the mongoDB outbound channel adapter.


public class MongoDBConfiguration {
    public MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(), "si4Db");
    @ServiceActivator(inputChannel = "storeChannel")
    public MessageHandler mongodbAdapter() throws Exception {
        MongoDbStoringMessageHandler adapter = new MongoDbStoringMessageHandler(mongoDbFactory());
        adapter.setCollectionNameExpression(new LiteralExpression("courses"));
        return adapter;


Like the web service gateway, we can’t set the input channel to the adapter. I also have done that by specifying the input channel in the @ServiceActivator annotation.

4 Detail of the endpoints

The first endpoint of the flow is the integration gateway, which will put the argument (courseId) into the payload of a message and send it to the request channel.

@MessagingGateway(name = "entryGateway", defaultRequestChannel = "requestChannel")
public interface CourseService {
    public String findCourse(String courseId);


The message containing the course id will reach the transformer. This endpoint will build the request object that the web service is expecting:

public class CourseRequestBuilder {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Transformer(inputChannel="requestChannel", outputChannel="invocationChannel")
    public GetCourseRequest buildRequest(Message<String> msg) {
        logger.info("Building request for course [{}]", msg.getPayload());
        GetCourseRequest request = new GetCourseRequest();
        return request;


Subscribed to the response channel, which is the channel where the web service reply will be sent, there’s a service activator that will receive the response message and deliver the course name to the client:

public class CourseResponseHandler {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    public String getResponse(Message<GetCourseResponse> msg) {
        GetCourseResponse course = msg.getPayload();
        logger.info("Course with ID [{}] received: {}", course.getCourseId(), course.getName());
        return course.getName();


Also subscribed to the response channel, a filter will decide based on its type, if the course is required to be stored to a database:

public class StoredCoursesFilter {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Filter(inputChannel="responseChannel", outputChannel="storeChannel")
    public boolean filterCourse(Message<GetCourseResponse> msg) {
        if (!msg.getPayload().getCourseId().startsWith("BC-")) {
            logger.info("Course [{}] filtered. Not a BF course", msg.getPayload().getCourseId());
            return false;
        logger.info("Course [{}] validated. Storing to database", msg.getPayload().getCourseId());
        return true;


5 Testing the entire flow

The following client will send two requests; a BC type course request that will be stored to the database and a DF type course that will be finally filtered:

public class TestApp {
    CourseService service;
    public void testFlow() {
        String courseName = service.findCourse("BC-45");
        assertEquals("Introduction to Java", courseName);
        courseName = service.findCourse("DF-21");
        assertEquals("Functional Programming Principles in Scala", courseName);


This will result in the following console output:

CourseRequestBuilder|Building request for course [BC-45]
CourseResponseHandler|Course with ID [BC-45] received: Introduction to Java
StoredCoursesFilter|Course [BC-45] validated. Storing to database
CourseRequestBuilder|Building request for course [DF-21]
CourseResponseHandler|Course with ID [DF-21] received: Functional Programming Principles in Scala
StoredCoursesFilter|Course [DF-21] filtered. Not a BF course

6 Conclusion

We have learnt how to set up and test an application powered with Spring Integration using no XML configuration. Stay tuned, because Spring Integration Java DSL with Spring Integration extensions is on its way!

I’m publishing my new posts on Google plus and Twitter. Follow me if you want to be updated with new content.


14 thoughts on “Spring Integration 4.0: A complete XML-free example

  1. Hello, Xavier!

    Very-very nice and cool post!

    I happy to see that the last our decision to concentrate on Annotations configuration made a stuff!
    And it makes already sense even without Java DSL 🙂

    To improve your code a bit:

    In the last hours before release we provided more power to the Messaging Annotations and now they can be applied for the `@Bean` methods.
    In your case you can mark `wsOutboundGateway()` `@Bean` with `@ServiceActivator(inputChannel = "invocationChannel")` and get rid of `MessageHandler` injection to the `MessageChannel` and `subscriber()`. The same for `mongodbAdapter()`.
    Here is more info: http://docs.spring.io/spring-integration/docs/latest-ga/reference/html/configuration.html#d4e13627

    Your Message Flow diagram looks cyclic, however the entry point is `Gateway`, so, would look better to move it to left corner.

    Out of topic, regarding Java DSL: https://github.com/spring-projects/spring-integration-extensions/wiki/Spring-Integration-Java-DSL-Reference
    Any feedbacks welcome!

    Thank you very much for your so public work!

  2. Hello Artem,

    Thank you very much for your positive feedback, I really appreciate it!

    I will try your suggestions and update the post with it. It will indeed make the code cleaner to annotate adapters rather than explicitly subscribing them to the channels.

    Regarding the diagram, you are right. I wanted to make clear that the service activator returns the response to the gateway but it may add confusion to where the start of the flow is. I will move the gateway to the left and change the last line to a dotted one. I hope it will be better this way.

    Java DSL looks good. I think it is really a necessary addition if you want to get rid of XML configuration. It will make the flow configuration to be more centralized, which seems to be the main pitfall against XML. I am looking forward to playing with it! 🙂

  3. Xavier,

    One more point about `subscriber()` from `MessageChannel` bean definitions. We discussed with Gary your solution a bit and found that it is "anti-pattern" and fully isn't recommended for real applications. You lose Ednpoint here and the Lifecycle control over MessageHandler and that MessageChannel.

    However recently we introduced a breaking thing – `FixedSubscriberChannel`. It really makes sense for current your solution. 🙂

  4. I updated the post with the new diagram and subscription changes.

    I have finally chosen to use @ServiceActivator annotation in channel adapters since this allows us to avoid message handlers injection to message channels.

  5. This is really a nice post. I also tried a java configuration for tcp and udp channel but stuck within it. Can anyone help me out ?

  6. Thanks, Xavier. I have bookmarked that post, and as a matter of fact I am currently in the process of converting our XML configs to Java based config. Some of our flows are a bit complex, so I was hesitant to migrate to the DSL realm, because one of the Spring Integration tutorial videos made a suggestion to avoid DSL if your flows are complex. What is your opinion on that?

  7. I used XML configuration when I used SI in my job, since DSL wasn't there yet. However, I really feel the flow with DSL is much more readable than with xml. I wonder what the cause would be to suggest avoiding DSL in those videos

  8. Hi Xavier,

    Thank You for the very nice post. It was very helpful. I have a question regarding the following diagram. I know you could get a flow diagram view in STS (IDE) if you are using an XML configuration. However, in your case you have it all done in Java (Which is nice) but you still have managed to get the diagram somehow. Can you please explain how to get the diagram with Java Configuration ? It would be VERY useful to visualize the flow rather than trying to connect the dots looking at code.

Leave a Reply

Your email address will not be published. Required fields are marked *