Discussions

WebWork and Spring both play nicely with others. There are a couple of ways to integrate between the two of them, and Christian Parker writes about the various options. Specifically he looks at the multiple ways in which you can use spring-managed beans from webwork actions.

Actually, there is a better way to accomplish the same task. As part of the xwork-optional package at xwork.dev.java.net, you can use the SpringObjectFactory to instantiate your Webwork actions as Spring beans. You can view an example at http://wiki.opensymphony.com/display/WW/Spring. This method has a couple of benefits over the external reference method. One benefit is your xwork.xml will not have any dependency on Spring in its configuration. Also, your Action classes will be Spring beans so they can take advantage of everything Spring has to offer.

I just recently adding Spring support for webwork actions in a project I'm working on and am quite happy with the external-ref approach. I like it because it keeps Spring separate from webwork, and is pretty easy to understand. I suppose the objectfactory approach has its advantages but the one major disadvantage I can see is that you automatically double the amount of configuration code you need for an action. Not only do you have to configure the action with all of its results in xwork.xml, you also have to configure the action as a bean in Spring. While this may offer certain advantages if you're using other aspects of Spring, I find the extra configuration to be more of a burden if all you want is dependency injection.

I'd also be curious to see what the difference is in overhead with spring as opposed to xwork instantiating and wiring actions and interceptors. I don't know why one would be faster or slower than the other, but it would be interesting. Though I do have some concern with using Spring to handle interceptors, since they're so intrinsic to xwork; I'm guessing that there may be certain optimizations and other things going on that Spring might not be geared towards. It strikes me as similar to using Spring but substituting something else for dependency injection, since interceptors are so core to webwork's functionality.

I would disagree that the ObjectFactory approach doubles your configuration code. It's more accurate to say that it splits it up between the applicatonContext.xml and xwork.xml. The external refs get moved to the Spring xml, and you can refer to your Spring actions with aliases in xwork.xml. The main reason I switched over from using external-refs to the ObjectFactory is because it allows me to wrap my Xwork actions in Spring-driven transactions, and BeanNameAutoProxyCreator makes it a piece of cake to add this and other functionality as well, such as Acegi security. But to each his own. Two config files isn't so bad after you've spent years in deployment descriptor hell.

Interesting take on the ObjectFactory approach. I was against it for the same reasons that Drew mentioned above about having to touch two config files when adding an action. I hadn't considered actually wrapping the action in a spring transaction though. Interesting. I suppose if your are calling your DAO multiple times within one action then this is necessary.

Either way I should have included the ObjectFactory approach in the article. Thanks for pointing it out!

Ditto on the beauty of only dealing with xwork.xml and applicationContext.xml v.s. 5 files for an EJB! ;)

Interesting take on the ObjectFactory approach. I was against it for the same reasons that Drew mentioned above about having to touch two config files when adding an action. I hadn't considered actually wrapping the action in a spring transaction though. Interesting. I suppose if your are calling your DAO multiple times within one action then this is necessary.Either way I should have included the ObjectFactory approach in the article. Thanks for pointing it out!Ditto on the beauty of only dealing with xwork.xml and applicationContext.xml v.s. 5 files for an EJB! ;)CP

One reason I chose the Action as my transaction boundary is so I can access and/or filter lazy Hibernate collections before the transaction closes the Session. I also have several Actions that use multiple DAO's.

Plus it allows me to add Acegi security interception at the Action level rather than just the DAO level.

Have you done all of the following -->-used BeanNameAutoProxyCreator-proxyied by class-mapping the actions to a method (say "save") rather than the interface "execute"?Did it work???Matt

Matt. Yes, this is the method I use. However, there is a bug in Spring 1.0.2 (fixed in 1.1) that prevents this from working correctly. I had to build Spring from CVS Head in order to use it. The recently released 1.1 RC1 should work.

As I said, if you're using something in Spring other than DI (like transactions), then I guess the objectfactory approach would make sense. I'm still leery of editing the same thing in 2 different files, though. Also, if you're spanning a transaction over the course of your action, such as several DAO calls, wouldn't you rather put that behind some sort of facade? That way it can be used again by something not webwork related, if necessary. I'm a bit loathe to allow my web layer to control much more than the process of translating requests to and from my business layer, so I would prefer to leave the transactions in Spring, behind Spring-managed facades, and link them up explicitly to the webwork actions. To each his own, however.

I agree with the other poster about the idea of having Spring do its magic automatically, the way the ComponentInterceptor works. Though I'm not quite sure how that would be possible or efficient, since the component interceptor uses interfaces to define injection points (Type 1 IoC, if I'm not mistaken!).

re: Though I'm not quite sure how that would be possible or efficient, since the component interceptor uses interfaces to define injection points (Type 1 IoC, if I'm not mistaken!)

Make it work the same way it works not, the enabler would be the same.The "class" however would be a bean id from spring.

If the object implements the enabler all is good.<component><scope>application</scope><!-- just like how class works not for actions as spring integration --> <class>persistenceManager</class> <enabler>com.diamondip.ipc.persistence.hibernate.SessionFactoryAware</enabler></component>

Though if your were going to make this change. "external ref" or "alias" might be more clear than "class".

As I said, if you're using something in Spring other than DI (like transactions), then I guess the objectfactory approach would make sense. I'm still leery of editing the same thing in 2 different files, though. Also, if you're spanning a transaction over the course of your action, such as several DAO calls, wouldn't you rather put that behind some sort of facade? That way it can be used again by something not webwork related, if necessary. I'm a bit loathe to allow my web layer to control much more than the process of translating requests to and from my business layer, so I would prefer to leave the transactions in Spring, behind Spring-managed facades, and link them up explicitly to the webwork actions.

Drew.

I guess it depends on how you view your action objects. My view is that XWork actions make up the business layer, implementing business logic and calling DAO's. The actions are completely independent of any Web API's, as I have SOAP and XML/HTTP services that also invoke XWork actions/commands by way of XWork's ActionFactory (Btw, that's also how I unit test them). My web/presentation layer consists strictly of velocity templates that the ActionResult forwards to.

However, there are still some problems with this setup -->--->Duplication of declaring my actions

Transactions --> I would like various actions to execute in transactions. However, I don't want to define an proxy for every action. I could use the BeanNameAutoProxyCreator, but this fails whenI dont' proxy by interface(don't want to write an interface for every action) AND I am mapping this to a method of the action rather than the default "execute()".

Execute works because, if there is no method mapped xwork just casts the action to the Action interface and everything works very well.

Problems arise since you can't use the standard reflection api to invoke "delete" on the cglib proxy'd object.

I gave up on trying to auto define transactions on my actions. Instead, I have define <interceptor-ref name="transaction"/> on the actions that need to run in transactions.This xwork interceptor is pretty much a no-opp interceptor that just does.

<!-- This is an Xwork interceptor, runs the intercepted action as a transaction, this object gets optionallly added as an xwork interceptor --> <bean id="myActionTransactionInterceptor" class="com.diamondip.ipcontrol.persistence.TransactionInterceptor" />

It would be nicer if there was a spring enabled version of xwork's "component" interceptor.That way, you don't have to explicitly say "external-ref", except when you want to be exact. <external-ref name="actionDAO">MainDAO</external-ref>

This would be pretty easy to do... You could have a very simple interceptor which just does this:<code>((ConfigurableApplicationContext)appContext).getBeanFactory().autowireBeanProperties(bean,AutowireCapableBeanFactory.AUTOWIRE_BY_NAME,false)</code>... you could even parameterize it with whether it should do by type or by name.

Problems arise since you can't use the standard reflection api to invoke "delete" on the cglib proxy'd object.

TechTarget provides technology professionals with the information they need to perform their jobs - from developing strategy, to making cost-effective purchase decisions and managing their organizations technology projects - with its network of technology-specific websites, events and online magazines.