Blog

Mule Integration with Spring: A New Approach

by | Apr 29, 2014 | Software Development | 1 comment

I’ve written about using Mule with Spring on my personal blog.  In this article I described how to integrate Mule into an existing Spring MVC application.

That approach involved configuring the web.xml file to setup a Mule context:

    <listener>
        <listener-class>org.mule.config.builders.MuleXmlBuilderContextListener</listener-class>
    </listener>
    <context-param>
        <param-name>org.mule.config</param-name>
        <param-value>spring-rma.xml</param-value>
    </context-param>

This approach is easy and works well, especially if all your Spring beans are defined in Mule files.  But my application already had a Spring application context with a large library of Spring beans.  The above approach creates a whole separate context!  My Mule flows have no access to my existing Spring beans!  This situation is very depressing in terms of having Mule be able to leverage my existing code.

So I found a better way.  I now create the Mule context as a child of my main Spring application context.  My problem is completely resolved!  It does take a little more work.

First, create a Spring bean to manage the Mule context.  Spring calls methods on this bean when the application context is started, and again when the application context is closing.  These methods start the Mule context when Spring starts, and closes it when Spring is shutting down.  It also has a list of Mule configuration files to include in the Mule context.

package com.armedia.acm.rma;

import org.mule.api.MuleContext;
import org.mule.api.MuleException;
import org.mule.api.context.MuleContextFactory;
import org.mule.config.spring.SpringXmlConfigurationBuilder;
import org.mule.context.DefaultMuleContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MuleContextManager implements ApplicationContextAware
{

    private MuleContext muleContext;
    private transient Logger log = LoggerFactory.getLogger(getClass());
    private ApplicationContext applicationContext;
    private String[] configurationFiles;

    private void startMuleContext(ApplicationContext applicationContext) throws MuleException
    {
        if ( getMuleContext() != null )
        {
            return;
        }
        log.debug("Creating spring config builder.");
        SpringXmlConfigurationBuilder builder = new SpringXmlConfigurationBuilder(getConfigurationFiles());

        builder.setParentContext(applicationContext);
        MuleContextFactory muleContextFactory = new DefaultMuleContextFactory();
        MuleContext muleContext = muleContextFactory.createMuleContext(builder);

        log.debug("Starting mule context");
        muleContext.start();
        setMuleContext(muleContext);
        log.debug("Done.");
    }

    public void shutdownBean()
    {
        try
        {
            if ( getMuleContext() != null )
            {
                log.debug("Stopping Mule context");
                getMuleContext().stop();
            }
        }
        catch (MuleException e)
        {
            log.error("Could not stop Mule context: " + e.getMessage(), e);
        }
    }

    public MuleContext getMuleContext()
    {
        return muleContext;
    }

    public void setMuleContext(MuleContext muleContext)
    {
        this.muleContext = muleContext;
    }

    public ApplicationContext getApplicationContext()
    {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
    {
        this.applicationContext = applicationContext;

        if ( getMuleContext() == null )
        {
            try
            {
                startMuleContext(applicationContext);
            }
            catch (MuleException e)
            {
                log.error("Could not start Mule context: " + e.getMessage(), e);
                throw new IllegalStateException(e);
            }
        }
    }

    public String[] getConfigurationFiles()
    {
        return configurationFiles;
    }

    public void setConfigurationFiles(String[] configurationFiles)
    {
        this.configurationFiles = configurationFiles;
    }
}

The above bean is configured in Spring like so:

    <bean id="muleContextManager" class="com.armedia.acm.rma.MuleContextManager"
            destroy-method="shutdownBean">
        <property name="configurationFiles">
            <array>
                <value type="java.lang.String">spring-rma.xml</value>
            </array>
        </property>
    </bean>

Now must make sure this Spring XML configuration is in your Spring application context, and all is well. Mule still starts and stops when the Web application starts and stops, just like with the original method. And, since we make the Mule context a child of the Spring context (Line 30 in the above Java code), all Mule flows can see all the Spring beans. Life is good!

Don’t forget to remove the Mule configuration elements from the web.xml!!!

Coincidence… or Fate?  A true story postscript.

I wrote the above Java code yesterday.  When I got home, the new book “Mule in Action, Volume 2” was in my mailbox.  I opened the book to a random page: page 209, to be exact.  This page includes a code snippet.  It was the same code I just wrote – the same code you see above!  I was reading the very code I had written earlier that day!  Weird, but true.

Categories

1 Comment

  1. Pete Kasson

    Great article. Do you know how one could scan a mule project (xml) and extract all the flow details, flow steps, subflows, etc, in a flow so they can be cataloged / analyzed ? Thanks!

    Reply

Submit a Comment

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