tags:

views:

176

answers:

3

I couldn't find a definitive answer to this in the docs, and although there seems to be a logical answer, one can't be sure. The scenario is this - you have a xml-based transaction definition, like:

<tx:advice id="txAdvice" transaction-manager="jpaTransactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

Which advises all service methods. But then you have @Transactional on a concrete class/method, where you want to override the propagation attribute.

It is clear that @Transactional at method-level overrides the same one at class-level, but does it override the <tx:advice> (and actually, the <aop:pointcut>)?

I hope two interceptors won't be created on the same class, (and whichever happens to be first will start the transaction)

+2  A: 

After a bit of digging, I think the answer lies in TxAdviceBeanDefinitionParser.doParse. The logic says:

if <tx:attributes> is present then
   parse <tx:attributes> 
else
   instantiate an AnnotationTransactionAttributeSource to determine TX attributes

Given the only thing that reads @Transactional is AnnotationTransactionAttributeSource, that strongly suggests to me that <tx:advice> will consult @Transactional if and only if <tx:attributes> is not specified, so no overriding is possible.

This does seem to contradict Spring's usual "principle of least surprise" approach, since like you I would have expected the annotation to take precedence on a per-class or per-method basis. I would file an issue on their JIRA to get this behaviour changed.

Having said all that, I still think it's worth giving this a try to see what it does, since it may work by some other mechanism.

skaffman
interestingly, it behaves as we have expected. I'll now do some digging as well to see what more is there to TxAdviceBeanDefinitionParser..
Bozho
I wonder if the proxy generated by `TxAdviceBeanDefinitionParser` is checking the target bean for annotations when invoked.
skaffman
it turns out my guess about two TransactionInterceptors being created is true. I asked the question (including my new findings) at the spring forum, and will keep you updated with the result.
Bozho
Is there also a `<tx:annotation-driven>` in your context? That would trigger the additional proxy creation.
skaffman
yes, there is. otherwise the @Transactional wouldn't be taken into account at all.
Bozho
+1  A: 

Thanks to skaffman for his effort. Finally I think I got the behaviour:

  1. Both <aop:advisor> and @Transactional (together with <tx:annotation-driven>) create a TransactionInterceptor around the target class (the one, whose methods are to be run in transaction).
  2. The advice with a lower order attribute overrides the other one. If no order attribute is specified, the order is undefined. But my tests showed that the one defined latest in the applicationContext.xml takes precedence, although this might not be the case always:

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined.

At least this is the behaviour for spring 2.5.6.

Bozho
A: 

Does anyone know why it is not working the way Bozho described?

I would like not to use any annotation for transaction management, except the few methods where propagation must be PROPAGATION_REQUIRES_NEW. That would definitely be Convention over Configuration (also known as Coding by convention).

And is it going to work this way in the future?

ewsnatcher
1. this should be a comment, not an answer. 2. I described the actual behaviour in my own answer, and it works that way in both 2.5 and 3.0
Bozho