Get the files you need to externally resolve Spring beans. I‘ve bundled them all here: http://www.ryandaigle.com/pebble/images/webwork2-spring.jar
Now, let‘s get your XWork configuration file (xwork.xml) to resolveexternal references. XWork resolves external references (using theexternal-ref element) by utilizing an external reference resolver perpackage. You specify your external reference resolver as an attributeof the package element:
<package name="default" extends="webwork-default"
externalReferenceResolver="com.atlassian.xwork.ext.SpringServletContextReferenceResolver">
This SpringServletContextReferenceResolver class reference is aclass not part of the XWork distribution written as an extensions forXWork/Spring that I got from this JIRA issue filed against XWorkaddressing this Spring integration effort. (I have bundled it with therest of the necessary files later on down for your convenience). Thisclass will intercept all external-refs and resolve the references usingSpring‘s context. There is also aSpringApplicationContextReferenceResolver included in the zip file thatwill allow you to resolve Spring references for applications notexecuting within the web context. But as this is a WebWork/Springarticle, the servlet resolver is what we need to use.
Now we need to add the XWork reference resolver as part of theinterceptor stack you‘re using. This will allow any references to beresolved (using the reference resolver you specified in theexternalReferenceResolver attribute). This is how I‘ve added thatinterceptor:
<interceptors>
<interceptor name="reference-resolver" class="com.opensymphony.xwork.interceptor.ExternalReferencesInterceptor"/>
<interceptor-stack name="myDefaultWebStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="reference-resolver"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myDefaultWebStack"/>
As I briefly outlined before, you can now reference Spring beans that your action classes need in xwork.xml:
<action name="myAction" class="com.ryandaigle.web.actions.MyAction">
<external-ref name="DAO">myDAO</external-ref>
<result name="success" type="dispatcher">
<param name="location">/success.jsp</param>
</result>
</action>
And that‘s all we have to do to xwork.xml to let XWork know how to resolve references to Spring‘s managed beans.
Now let‘s setup our web environment to properly notify Spring andour external reference resolver of the web context. We do this byadding two context listeners to your application‘s web.xml file:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.atlassian.xwork.ext.ResolverSetupServletContextListener</listener-class>
</listener>
The first listener is Spring‘s that you would need independent ofwhether or not you were integrating with WebWork 2. The second listeneris our external resolver‘s that will use the servlet context toretrieve Spring‘s application context. This is the link between WebWorkand Spring.
At this point, we‘ve set up Spring and our XWork reference resolver towork within a web context, and we‘ve told XWork how to resolve externalreferences to Spring. We‘re done! Fire it up and let me know if thereare some steps I‘ve missed or assumptions I‘ve made that I shouldn‘thave.
Judging by the comments etc... of the JIRA issues filed against XWork, it appears that Ross Mason (of Atlassian?) is the man to thank for the external reference resolver code. And of course we have to thank the people of Spring and WebWork 2 for making this all possible.
Rather than using an external reference resolver with releases ofXWork from 1.0.1 and onwards, it‘s possible to use theSpringObjectFactory from the xwork-optional
<bean name="some-action" class="fully.qualified.class.name" singleton="false">
<property name="someProperty"><ref bean="someOtherBean"/></property>
</bean>
Within xwork.xml:
<action name="myAction" class="some-action">
<result name="success">view.jsp</result>
</action>
Notice that the XWork Action‘s class name is the bean name defined in the Spring application context.
The 1.1.3 release of the Spring/XWork integration library allows the user to configure everything in the xwork.xml file without needing to add extra entries to the applicationContext.xml.This is done by configuring the actions with the fully qualified classname (as if not using the SpringObjectFactory) It also added theability to make use of constructor-based dependency injection withoutany further changes. The major caveat when using constructor-based DIis that objects passed in to the constructor must be unambiguous withinthe applicationContext (as is normally required by Spring) If there isany ambiguity, then you can still configure things the more traditionalway, splitting the configuration of the action between xwork.xml and applicationContext.xml as described above.
One other advantage of the SpringObjectFactory approach is that itcan also be used to load interceptors using the same sort of logic. Ifthe interceptor is stateless, then it‘s possible to create theinterceptor as a singelton instance, but otherwise it‘s best to createit as a Spring prototype.
In order to be used, the default ObjectFactory that XWork usesshould be replaced with an instance of the SpringObjectFactory. Thexwork-optional package ships with a ContextListener that does this,assuming that the Spring application context has already beenconfigured.
Another alternative to using the SpringObjectFactory is to use theActionAutowiringInterceptor. The interceptor will autowire any actionclass based on the autowire strategy defined. An advantage to using theinterceptor over the SpringObjectFactory is that the action classes donot have to defined in the Spring‘s application context. The followingis an example of how it can be configured in xwork.xml:
<interceptors>
<interceptor name="autowire" class="com.opensymphony.xwork.spring.interceptor.ActionAutowiringInterceptor">
<param name="autowireStrategy">1</param>
</interceptor>
<interceptor-stack name="autowireDefault">
<interceptor-ref name="autowire"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
Note the the autowireStrategy parameter is optional. If you do notdefine it, then the SpringObjectFactory will default to autowiring byname. The interceptor looks for Spring‘s application context in theXWork‘s application context. To initialize the application context, addthe following listener to your web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
You do not have to configure the SpringObjectFactory seperatelyunless you plain on instantiating results, interceptors, or validatorsas Spring beans. As a convenience method to get access to theapplication context for other uses, it is placed in the ActionContextmap under the key ActionAutowiringInterceptor.APPLICATION_CONTEXT foreach Action.