Sunday, May 5, 2013

Spring annotation on interface or class implementing the interface??

A returning question with regard to Spring is whether to annotate interfaces or concrete classes with for instance the @Transactional annotation (and similar annotations, e.g. @Cacheable).

In the Spring documentation it states the following:

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.

But what does that really mean? Let me illustrate with a simple example:
public class Main {

    public static void main(String... args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("file:src/main/resources/META-INF/spring/app-context.xml");
        WithAnnotation bean = ctx.getBean(WithAnnotation.class);
        bean.someMethod();
    }
}


// I 'll play around with this
// @Transactional
interface WithAnnotation {
    void someMethod();
}

// I 'll play around with this
// @Transactional
@Component
class ConcreteClass implements WithAnnotation {

    public void someMethod() {
        System.err.println("In some method: " + TransactionInterceptor.currentTransactionStatus());
    };
}

Default configuration: proxy-target-class="false"

With a transaction configuration like this (the default):







If we run the program with the @Transactional uncommented on the interface we get:
...
In some method: org.springframework.transaction.support.DefaultTransactionStatus@5c76911d1
...

If we run the program with the @Transactional uncommented on the class (commenting out @Transactional on the interface again) we get:
...
In some method: org.springframework.transaction.support.DefaultTransactionStatus@5c76911d
...

In both cases the code executes in a transactional context as we would expect.

Non default configuration: proxy-target-class="true"

Now let's change the transaction configuration to this (the non default):


If we run the program with the @Transactional uncommented on the interface (commenting out @Transactional on the class again) we get:
...
Exception in thread "main" org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope
 at org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus(TransactionAspectSupport.java:110)
...

If we run the program with the @Transactional uncommented on the class (commenting out @Transactional on the interface again) we get:
...
In some method: org.springframework.transaction.support.DefaultTransactionStatus@4869a267
...

What have we learned?

If Spring can't create a JDK proxy (or we force it to create a cglib proxy by setting the proxy-target-class to "true") then the code will not execute in a transactional context (just like the Spring documentation stated).

A warning: if you remove the call to TransactionInterceptor.currentTransactionStatus() the code will run without trowing an exception, but it will not run in a transactional context. Yes, you read it: no exception, no warning and no transactional context even though you have got the @Transactional annotation on the interface. I guess that is what is meant by ...the object will not be wrapped in a transactional proxy, which would be decidedly bad :)

1 comment:

  1. The effectiveness of IEEE Project Domains depends very much on the situation in which they are applied. In order to further improve IEEE Final Year Project Domains practices we need to explicitly describe and utilise our knowledge about software domains of software engineering Final Year Project Domains for CSE technologies. This paper suggests a modelling formalism for supporting systematic reuse of software engineering technologies during planning of software projects and improvement programmes in Final Year Project Centers in Chennai.

    Spring Framework has already made serious inroads as an integrated technology stack for building user-facing applications. Spring Framework Corporate TRaining the authors explore the idea of using Java in Big Data platforms.
    Specifically, Spring Framework provides various tasks are geared around preparing data for further analysis and visualization. Spring Training in Chennai

    ReplyDelete