struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeroen De Ridder <voetsjo...@gmail.com>
Subject Re: @Transactional Spring Annotation in a Struts2 Action does not work
Date Fri, 01 May 2009 03:11:58 GMT
I'll agree that a service layer alone won't cut it, simply because of 
the way JPA/Hibernate works. Updating an instance for example is just 
something that doesn't belong in a service. I'm by no means an expert of 
best practices in JPA/Hibernate and Spring, but I've found a combination 
of services and anonymous runner interface instances to work quite well.

Basically, the idea is that you create a bunch of services to do routine 
stuff to improve code clarity and avoid code duplication in your 
actions. You'd mark these services with propagation=REQUIRED, so that 
they can run by themselves if needed as well as run along with any 
existing transactions. For logic that needs more than a single call to a 
service, I then do something like this:

txr.execute(new TransactionalExecution(){
    public void execute() {
                   
        Foo foo = fooService.getFoo(id);
        if(foo != null) throw new FooException("No such foo exists!");
       
        foo.setName(name);
       
    }
});

TransactionalExecution is just an interface with a single method 
execute() that exists just so we can create anonymous instances of it to 
pass to txr, which would be an instance of TransactionalExecutionRunner:

public class JpaSpringTransactionalExecutionRunner implements 
TransactionalExecutionRunner {
   
    @Transactional(propagation=Propagation.REQUIRED)
    public void execute(TransactionalExecution t) {
        t.execute();
    }
   
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void executeRequiresNew(TransactionalExecution t) {
        t.execute();
    }
   
    @Transactional(propagation=Propagation.MANDATORY)
    public void executeMandatory(TransactionalExecution t) {
        t.execute();
    }
   
}

(I'm sure you can figure out what the TransactionalExecutionRunner 
interface says). You'd then declare the transactionalExecutionRunner 
bean in your Spring context and have it injected into every action 
created by the Spring object factory through autowiring for example, and 
you're good to go. The cool thing about this is that your controller 
code stays very clear and to the point with minimal persistence bloat, 
and that any call to a service method from within a 
TransactionalExecution will automatically run within the ongoing 
transaction.

As for your configuration, other than your applicationContext.xml file 
you shouldn't have to do anything other than include the spring plugin 
jar in your classpath. The jar comes with a struts-default.xml file that 
sets Spring as the default object factory. Of course, it can never hurt 
to explicitly set the objectFactory; I'm using 
struts.objectFactory=org.apache.struts2.spring.StrutsSpringObjectFactory, 
but struts.objectFactory=spring should work equally well.

-- Jeroen

> Hi Jeroen,
>
> The problem is that I am not a big fan of services layer. Sometimes it looks
> very anemic to me. But I totally agree with you when you say the action
> should not know about persistence problems, and that's why I want to do it
> via AOP.
>
> I had the same thought about the problem: the Spring proxy does not work
> properly with all the magic Struts2 and Reflection do!
>
> I tried to open a bug in the Struts2 JIRA, but they closed it and said that
> it works. I think it should be some kind of spring or struts configuration I
> am not doing right.
>
> Thanks in advance,
> Mauricio
>
> On Thu, Apr 30, 2009 at 11:22 PM, Jeroen De Ridder <voetsjoeba@gmail.com>wrote:
>
>   
>> You really shouldn't be making your Struts 2 actions @Transactional. Doing
>> that causes Spring to create a proxy so it can put some extra
>> transaction-handling logic between the method call and the actual method.
>> The thing is, Struts 2 and OGNL rely heavily on reflection on the action
>> classes which simply does not work at all with the proxies created by
>> Spring.
>>
>> Regardless, making your actions @Transactional means mixing persistence
>> concerns with controller logic in the same class. You should consider
>> keeping the two separated. For example, the service approach is a good
>> start:
>> http://struts.apache.org/2.0.14/docs/struts-2-spring-2-jpa-ajax.html.
>>
>>
>>  Yes, I am. Everything works fine when I don't try to use Spring
>>     
>>> transactional AOP!
>>>
>>> Mauricio
>>>
>>> On Thu, Apr 30, 2009 at 9:43 PM, Dave Newton <newton.dave@yahoo.com>
>>> wrote:
>>>
>>>
>>>
>>>       
>>>> Mauricio Aniche wrote:
>>>>
>>>>
>>>>
>>>>         
>>>>> I am using Struts2+Spring+JPA/Hibernate. When I use the @Transactional
>>>>> to
>>>>> mark an execute() method in a Struts2 Action, the action stops working
>>>>> properly (i.e. the attributes in the action are not automatically
>>>>> setted).
>>>>> It does not work with Spring AOP transactions as well.
>>>>>
>>>>> In my struts.config I setted the following constant:
>>>>> ----
>>>>> <constant name="struts.objectFactory" value="spring" />
>>>>>
>>>>>
>>>>>
>>>>>           
>>>> You're using the Spring plugin, correct?
>>>>
>>>> Dave
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>> For additional commands, e-mail: user-help@struts.apache.org
>>>>
>>>>
>>>>
>>>>
>>>>         
>>>
>>>       
>>     
>
>   


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Mime
View raw message