Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Description

Info

Spring is

...

a lightweight container, providing centralized, automated configuration and wiring of your application objects, using a technique called "Dependency Injection"

The Spring Plugin works by overriding the Struts ObjectFactory to enhance the creation of core framework objects. When an object is to be created, it uses the class attribute in the Struts configuration to correspond to the id attribute in the Spring configuration. If not found, the class will try to be created as usual, then be autowired by Spring. In the case of Actions, Spring 2's bean scope feature can be used to scope an Action instance to the session, application, or a custom scope, providing advanced customization above the default per-request scoping.

Note
titleSpring Actions are Optional!

Remember: registering Actions with Spring is not required. The Spring alternative is there if you need it, but the framework will automatically create Actions objects from the action mappings. But, if you want to use Spring to inject your Actions, the option is there.

Features

  • Allow Actions, Interceptors, and Results to be created by Spring
  • Struts-created objects can be autowired by Spring after creation
  • Provides two interceptors that autowire actions, if not using the Spring ObjectFactory

Usage

To enable Spring integration, simply include struts2-spring-plugin-x-x-x.jar in your application.

If you are using more than one object factory, (for example, by including both the Spring and Plexus plugins in your application,) you will need to set the struts.objectFactory property in struts.properties or in one of several XML files via Constant Configuration:

Code Block
titlestruts.properties
struts.objectFactory = spring
Code Block
titlestruts.xml
<struts>
  <constant name="struts.objectFactory" value="spring" />
  ... 
</struts>

Autowiring

The framework enables "autowiring" by default. (Autowiring means to look for objects

Note

This section covers the only supported Spring integration technique. However, there are many other ways to tie in to Spring with WebWork. Please see Other Spring Integration for more info. Note that none of the other methods are currently supported and could change at any time!

Enabling Spring Integration

Turning on Spring support in WebWork is simply a matter of installing the latest Spring jars in to your classpath and then adding the following entry to webwork.properties:

Code Block
webwork.objectFactory = spring

If you want to change from the default autowiring mode, which is to auto-wire by name (i.e. to look for beans defined in Spring with the same name as your bean object property), then you'll also need a setting for this in your webwork.properties:. To change the wiring mode, modify the spring.autowire property.

Code Block
titleWiring Mode
struts
Code Block
webwork.objectFactory.spring.autoWire = type

Options for this setting are:The autowire property can be set to several options.

name

Auto-wire by matching the name of the bean in Spring with the name of the property in your action. This is the default

type

Auto-wire by looking for a bean registered with Spring of the same type as the property in your action. This requires you to have only one bean of this type registered with Spring

auto

Spring will attempt to auto-detect the best method for auto-wiring your action

constructor

Spring will auto-wire the parameters of the bean's constructor

no

Turn off externally defined autowiring. Annotation-driven injection and injection based on Springs *Aware-interfaces still applies

By default, the framework At this point, all objects will at least try to get created by Springuse Spring to create all its objects. If they the object cannot be created by Spring, then WebWork the framework will create the object itself. Next, you'll need to turn on the Spring listener in web.xml:.

Enabling Spring integration for other application objects is a two-step process.

  • Configure the Spring listener
Code Block
xml
xml
titleweb.xml
Code Block
xmlxml

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  • Register your objects via the Spring configuration
Code Block
xml
xml
titleapplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="autodetect">
    <bean id="personManager" class="com.acme.PersonManager" scope="prototype"/>
    ...
</beans>
Tip
titleMore ApplicationContext applicationContext configuration files needed?

Since the Spring integration uses a standard Listener, it can be configured to support configuration files other than applicationContext.xml.
Adding the following to your web.xml will cause Spring's ApplicationContext to be inititalized from all files matching the given pattern:

Code Block
xml
xml

<!-- Context Configuration locations for Spring XML files -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value>
</context-param>

See the Spring documentation for a full description of this parameter.

Sample Spring Configuration

At this point, you can add the standard Spring configuration at WEB-INF/applicationContext.xml. An example of this configuration is:

...


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="autodetect">
    <bean id="personManager" class="com.acme.PersonManager"/>
    ...
</beans>

Switching from Builtin IoC to Spring

Switching is quite easy. Spring setup is done as described above. To complete migration, you will have to

  1. transfer your configured components from components.xml to applicationContext.xml appropriately. You can safely delete components.xml afterwards.
  2. remove the Component Interceptor from your interceptor stack in xwork.xml. Although it does not hurt to leave it there, it is simply redundant from now on.
Note
titleSession Scope & Spring

Spring does not support session scoped components right now. There are plans for integrating this in the Spring 2.0 release. Right now, you will have to use Spring Session Components Workarounds.

Initializing Actions from Spring

Normally, in xwork struts.xml you specify the class for each actionAction. When using the SpringObjectFactory (configured as shown above) WebWork default SpringObjectFactory, the framework will ask Spring to create the action Action and wire up dependencies as specified by the default auto-wire behavior. The SpringObjectFactory will also apply all bean post processors to do things like proxy your action for transactions, security, etc. which Spring can automatically determine without explicit configuration. For most usages, this should be all you need for configuring your actions to have services and dependencies applied.

Tip

We strongly recommend that you find declarative ways of letting Spring know what to provide for your actions. This includes making your beans able to be autowired by either naming your dependent properties on your action the same as the bean defined in Spring which should be provided (to allow for name-based autowiring), or using autowire-by-type and only having one of the required type registered with Spring. It also can include using JDK5 annotations to declare transactional and security requirements rather than having to explicitly set up proxies in your Spring configuration. If you can find ways to let Spring know what it needs to do for your action without needing any explicit configuration in the Spring applicationContext.xml, then you won't have to maintain this configuration in both places.

However, sometimes you might want the bean to be completely managed by Spring. This is useful, for example, if you wish to apply more complex AOP or Spring-enabled technologies, such as Acegi, to your beans. To do this, all you have to do is configure the bean in your Spring applicationContext.xml and then change the class attribute from your WebWork action Action in the xwork struts.xml to use the bean name defined in Spring instead of the class name.

Your xwork struts.xml file would then have the action Action class attributes changed, leaving it like this:.

Code Block
xml
xml
titlestruts.xml

<!DOCTYPE xworkstruts PUBLIC
    "-//OpenSymphonyApache Software GroupFoundation//XWork 1DTD Struts Configuration 2.0//EN"
    "http://wwwstruts.opensymphonyapache.comorg/xworkdtds/xworkstruts-12.10.dtd">

<xwork><struts>
    <include file="webworkstruts-default.xml"/>

    <package name="default" extends="webworkstruts-default">
        <action name="foo" class="com.acme.Foo">
            <result>foo.ftl</result>
        </action>
    </package>

    <package name="secure" namespace="/secure" extends="default">
        <action name="bar" class="bar">
            <result>bar.ftl</result>
        </action>
    </package>
</xwork>struts>

Where you have a Spring bean defined in your applicationContext.xml named "bar". Note that the com.acme.Foo action Action did not need to be changed, because it can be autowired.

A typical spring configuration for bar could look as following.

Code Block
xml
xml
langtitleapplicationConext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="autodetect">
    <bean id="bar" class="com.my.BarClass" singleton="false"/>
    ...
</beans>
Note
TitleTake Note

Note the id attribute in the spring configuration corresponds to the class attribute in the xwork configuration. Also note that in the spring configuration, the singleton attribute is set to false. This would generally be the case that is desired as Webwork creates a new action class upon each request. Hence when Spring integration is used, this would be the desired behaviour. Making Springs singleton attribute false would allow this.

To use session-scoped components with Spring and Struts, see the Spring Session Components Workarounds analysis.

Class Reloading

The Spring plugin can be configured to automatically reload classes that change in the file system. This feature will enable code changes to be "hot deployed" without having to restart the web container. To enable this feature follow these steps:

  1. Set "struts.devMode" to "true"
  2. Set "struts.class.reloading.watchList" to a comma separated list of directories, or jar files (absolute or relative paths)
  3. Add this to web.xml:

    Code Block
    typexml
       <context-param>
           <param-name>contextClass</param-name>
           <param-value>org.apache.struts2.spring.ClassReloadingXMLWebApplicationContext</param-value>
       </context-param> 
    
  4. Add Apache Commons JCI FAM to the classpath. If you are using maven, add this to pom.xml

    Code Block
    typexml
       <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-jci-fam</artifactId>
           <version>1.0</version>
       </dependency> 
    

Letting the reloading class loader handle all the classes can lead to ClassCastException(s) because instances of the same classes loaded by different class loaders can not be assigned to each other. To prevent this problem we suggest that struts.class.reloading.acceptClasses is used to limit the classes loaded by the reloading class loader, so only actions are handled by it. This constant supports a comma separated list of regular expressions:

Code Block
typexml
<constant name="struts.class.reloading.acceptClasses" value="com\.myproject\.example\.actions\..*" />
Warning

This feature is experimental, and should never be used in production systems.

Settings

The following settings can be customized. See the developer guide.

Setting

Description

Default

Possible Values

struts.objectFactory.spring.autoWire

The autowire strategy

name

name,type,auto, or constructor

struts.objectFactory.spring.autoWire.alwaysRespect

Whether the autowire strategy should always be used, or if the framework should try to guess the best strategy based on the situation

false for backwards-compatibility

true or false

struts.objectFactory.spring.useClassCache

Whether to have Spring use its class cache or not

true

true or false

struts.class.reloading.watchList

List of jar files or directories to watch for changes

null

Comma separated list of absolute or relative paths to jars or directories

struts.class.reloading.acceptClasses

List of regular expressions of accepted class names

null

Comma separated list of regular expressions of classes that will be loaded by the reloading class loader(we suggest to add regular expressions so only action classes are handled by the reloading class loader)

struts.class.reloading.reloadConfig

Reload the runtime configuration (action mappings, results etc) when a change is detected in one of the watched directories

false

true or false

DEPRECATED: struts.objectFactory.spring.enableAopSupport

Uses different logic to construct beans to allow support AOP, it uses an old approach to create a bean, switch this flag if you have problems with Spring beans and AOP

false

true or false

Installation

This plugin can be installed by copying the plugin jar into your application's /WEB-INF/lib directory. No other files need to be copied or createdRemember: this is not required. This is only needed if you wish to override the default behavior when the action is created in WebWork by decorating it with Spring-enabled interceptors and IoC that cannot be automatically determined by Spring. Keep in mind that WebWork's Spring integration will do standard IoC, using whatever auto-wiring you specify, even if you don't explicitely map each action in Spring. So typically you don't need to do this, but it is good to know how this can be done if you need to.