Adding Spring Dependancy Injection to Struts2 Project

Version 4.1 by Ken McWilliams on 2012/03/10 20:02

This will add Spring for the purpose of dependancy injection(DI) to our project. We will create a simple example showing DI and we will bring spring up to the latest version (as of this writing 3.1.1 however this method should apply for the near future). 

This assumes that we are starting with a basic strusts2 application.

1) Add the struts2-spring-plugin

The maven coordinates are:

Artifact Id: struts2-spring-plugin

Group Id: org.apache.struts

Version: 2.3.1.2 (or whatever version of struts2 you are using)

2) Configure web.xml and add applicationContext.xml to our project.

web.xml will need to look like the following:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>  
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>  
    <welcome-file-list>
        <welcome-file>/index.action</welcome-file>
    </welcome-file-list>
</web-app>

Add applicationContext.xml to src/main/resources (same place log4j.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
            http://www.springframework.org/schema/jdbc
            http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/jee
            http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <context:annotation-config/>            
    <context:component-scan base-package="com.yourProjectBase" />

</beans>

Note the above contains more xml name spaces and schemas than nessasary for simple DI however it sets us up nicely for adding Java Persistene API in the next integration tutorial. 

Beyond the name spaces and schemas there are three things happening:

1) context:annotation-config is used to activate annotations in beans already registered in the application context. To better understand this and to learn how to avoid using xml to register beans altogether please read this very nice answer on stack overflow: Difference between <context:annotation-config/> vs <context:component-scan/>

2) Was also explained in the previous link.  It allows us to define beans outside of the applicationContext via annotations, for that we supply the package(s) which it will scan. Again the above link is very useful in understanding this.

Note: We will add our beans on the blank line preceding </beans>

3) Create a basic DI example

The following assumes the use of the conventions plugin.  For explanation of this plugin see: using the convention plugin.

Our example will require the following things: 1) A service, 2) an implementation of the service, 3) configure spring to inject our service where we need it, 4) an action to use the service and 5) a view.  

Create Service

package com.example.project.service;

public interface Test {
    String doTest();
}

Create Service Implementation

package com.example.project.impl;
import com.example.project.service.Test;

public class TestImpl implements Test{
    @Override
    public String doTest() {
        return "From test.";
    }  
}

Configure Spring to Inject the Service

In applicationContext.xml add the following on the line before </beans>:

<bean id="test" class="com.example.project.impl.TestImpl"/>

Create an Action to use the Bean

package com.example.project.action.test;

import com.example.project.service.Test;
import com.opensymphony.xwork2.ActionSupport;
import org.springframework.beans.factory.annotation.Autowired;

public class SpringTest extends ActionSupport{
    @Autowired Test test;
    public String output;
    @Override
    public String execute(){
        output = test.doTest();
        return SUCCESS;
    }
}

The View

Create the JSP /WEB-INF/content/test/spring-test.jsp

<%@taglib prefix="s" uri="/struts-tags"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Spring Test</title>
    </head>
    <body>
        <h1>Spring Test</h1>
        Value from spring bean: <s:property value="output"/>
    </body>
</html>

Run the example... and append test/spring-test to the end of your application path and you should see the result.