Integrating Spring With Struts

Note: this applies to Struts 1.x (it was written before Struts 2.0)

If you use Struts, you can benefit from Spring, even if you do not want to switch to Spring MVC.

The simplest way to use Spring from within Struts is to call WebApplicationContextUtils.getWebApplicationContext(servletContext)
.getBean(beanName)
from with your Struts Action to get a handle on a Spring bean that provides the business logic for your action. This is fine, but it would be nice to be able to use IoC so that the dependencies can be externalized, therefore making the Action easier to test.

Well, we’re in luck. With the assistance of the DelegatingActionProxy and the ContextLoaderPlugIn, we can define our Struts Actions in our Spring configuration where we can inject dependencies that will be used in the Action. We can then use the DelegatingActionProxy as the type in our struts-config.xml file, which will serve as a proxy for the actual Action bean defined in the Spring configuration. When using the DelegatingActionProxy as the action type, the default behavior is that the path defined in the struts-config.xml action mapping will be used as the key to look up the actual action in the Spring configuration.

Here’s an example of how this works. Write your Action as you normally would, but design it with dependency injection. In this case, we will do the Widget list example, and we will make the WidgetDAO an injected dependency. Here’s it is:

public class WidgetListAction extends Action
{
  private WidgetDAO widgetDAO;

  public void setWidgetDAO(WidgetDAO widgetDAO)
  {
    this.widgetDAO = widgetDAO;
  }

  /**
   * The excecute method to get the widgets
   * and forward to the widget-list-view
   */
  public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
                               throws Exception
  {
    Collection widgets = widgetDAO.getWidgets();
    request.setAttribute("widgets", widgets);
    return mapping.findForward("widget-list-view");
  }
}

Now, to get the WidgetDAO injected via Spring, we need to define our action in Spring. So build a file named action-servlet.xml and wire up your action like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  <!-- Struts Action for Displaying Widget List -->
  <bean name="/widgetListAction"
        class="com.zabada.springrecipes.struts.WidgetListAction">
    <!-- WidgetDAO defined in parent applicationContext.xml -->

    <property name="widgetDAO"><ref bean="widgetDAO"/></property>
  </bean>
</beans>

The name of the bean is important. This must correspond exactly to the path for the corresponding action that we will define in struts-config.xml. Please Note - Make sure to use the bean name attribute in place of the id attribute when defining your action in Spring, like this: <bean name=”/actionName”/> not like this:<bean id=”/actionName”/>. XML parsers will not like the forward slash if you are using the id attribute.

Now, configure the action definition in struts-config.xml. We must set the type to org.springframework.web.struts.DelegatingActionProxy. This proxy finds and uses the actual version of the Struts action that we defined in action-servlet.xml.

Here is the action-mapping:

  <action-mappings>
    <action
      path="/widgetListAction"
      type="org.springframework.web.struts.DelegatingActionProxy"
      scope="request">
    </action>
  </action-mappings>

Finally, we must add the Spring ContextLoaderPlugIn to the struts-config.xml:

  <plug-in
    className="org.springframework.web.struts.ContextLoaderPlugIn">
  </plug-in>

That’s it!

IN A NUTSHELL

Steps for moving Struts Actions into a Spring Web Application Context in order to be able to inject dependent beans into the action:

  • Add the ContextLoaderPlugIn to the struts-config.xml
  • For each action in struts-config.xml, define the action in a Spring config XML named action-servlet.xml. You will have access to beans defined in the root application context (applicationContext.xml), therefore you can inject dependencies as needed directly onto your actions. The name property of the Spring bean in action-servlet.xml should be named the same as the action path for the corresponding action in struts-config.xml.
  • For each action in struts-config.xml replace the type with “org.springframework.web.struts.DelegatingActionProxy”

Other Resources

Next: Simplifying JDBC with the Spring JDBC Abstraction Framework