Spring - #Transactional - What happens in background? - java

I want to know what actually happens when you annotate a method with #Transactional?
Of course, I know that Spring will wrap that method in a Transaction.
But, I have the following doubts:
I heard that Spring creates a proxy class? Can someone explain this in more depth. What actually resides in that proxy class? What happens to the actual class? And how can I see Spring's created proxied class
I also read in Spring docs that:
Note: Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with #Transactional!
Source: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Why only external method calls will be under Transaction and not the self-invocation methods?

This is a big topic. The Spring reference doc devotes multiple chapters to it. I recommend reading the ones on Aspect-Oriented Programming and Transactions, as Spring's declarative transaction support uses AOP at its foundation.
But at a very high level, Spring creates proxies for classes that declare #Transactional on the class itself or on members. The proxy is mostly invisible at runtime. It provides a way for Spring to inject behaviors before, after, or around method calls into the object being proxied. Transaction management is just one example of the behaviors that can be hooked in. Security checks are another. And you can provide your own, too, for things like logging. So when you annotate a method with #Transactional, Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.
Transactions in EJB work similarly, by the way.
As you observed, through, the proxy mechanism only works when calls come in from some external object. When you make an internal call within the object, you're really making a call through the this reference, which bypasses the proxy. There are ways of working around that problem, however. I explain one approach in this forum post in which I use a BeanFactoryPostProcessor to inject an instance of the proxy into "self-referencing" classes at runtime. I save this reference to a member variable called me. Then if I need to make internal calls that require a change in the transaction status of the thread, I direct the call through the proxy (e.g. me.someMethod().) The forum post explains in more detail.
Note that the BeanFactoryPostProcessor code would be a little different now, as it was written back in the Spring 1.x timeframe. But hopefully it gives you an idea. I have an updated version that I could probably make available.

When Spring loads your bean definitions, and has been configured to look for #Transactional annotations, it will create these proxy objects around your actual bean. These proxy objects are instances of classes that are auto-generated at runtime. The default behaviour of these proxy objects when a method is invoked is just to invoke the same method on the "target" bean (i.e. your bean).
However, the proxies can also be supplied with interceptors, and when present these interceptors will be invoked by the proxy before it invokes your target bean's method. For target beans annotated with #Transactional, Spring will create a TransactionInterceptor, and pass it to the generated proxy object. So when you call the method from client code, you're calling the method on the proxy object, which first invokes the TransactionInterceptor (which begins a transaction), which in turn invokes the method on your target bean. When the invocation finishes, the TransactionInterceptor commits/rolls back the transaction. It's transparent to the client code.
As for the "external method" thing, if your bean invokes one of its own methods, then it will not be doing so via the proxy. Remember, Spring wraps your bean in the proxy, your bean has no knowledge of it. Only calls from "outside" your bean go through the proxy.
Does that help?

As a visual person, I like to weigh in with a sequence diagram of the proxy pattern. If you don't know how to read the arrows, I read the first one like this: Client executes Proxy.method().
The client calls a method on the target from his perspective, and is silently intercepted by the proxy
If a before aspect is defined, the proxy will execute it
Then, the actual method (target) is executed
After-returning and after-throwing are optional aspects that are
executed after the method returns and/or if the method throws an
exception
After that, the proxy executes the after aspect (if defined)
Finally the proxy returns to the calling client
(I was allowed to post the photo on condition that I mentioned its origins. Author: Noel Vaes, website: https://www.noelvaes.eu)

The simplest answer is:
On whichever method you declare #Transactional the boundary of transaction starts and boundary ends when method completes.
If you are using JPA call then all commits are with in this transaction boundary.
Lets say you are saving entity1, entity2 and entity3. Now while saving entity3 an exception occur, then as enitiy1 and entity2 comes in same transaction so entity1 and entity2 will be rollback with entity3.
Transaction :
entity1.save
entity2.save
entity3.save
Any exception will result in rollback of all JPA transactions with DB.Internally JPA transaction are used by Spring.

All existing answers are correct, but I feel cannot give this complex topic justice.
For a comprehensive, practical explanation you might want to have a look at this Spring #Transactional In-Depth guide, which tries its best to cover transaction management in ~4000 simple words, with a lot of code examples.

It may be late but I came across something which explains your concern related to proxy (only 'external' method calls coming in through the proxy will be intercepted) nicely.
For example, you have a class that looks like this
#Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
and you have an aspect, that looks like this:
#Component
#Aspect
public class CrossCuttingConcern {
#Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
public void doCrossCutStuff(){
System.out.println("Doing the cross cutting concern now");
}
}
When you execute it like this:
#Service
public class CoreBusinessKickOff {
#Autowired
CoreBusinessSubordinate subordinate;
// getter/setters
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
subordinate.doSomethingSmall(4);
}
}
Results of calling kickOff above given code above.
I do something big
Doing the cross cutting concern now
I did something small
Doing the cross cutting concern now
I also do something small but with an int
but when you change your code to
#Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
doSomethingSmall(4);
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
//subordinate.doSomethingSmall(4);
}
You see, the method internally calls another method so it won't be intercepted and the output would look like this:
I do something big
Doing the cross cutting concern now
I did something small
I also do something small but with an int
You can by-pass this by doing that
public void doSomethingBig() {
System.out.println("I did something small");
//doSomethingSmall(4);
((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
}
Code snippets taken from:
https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/
The page doesn't exist anymore.

Related

Diagnosing transactional exceptions in Spring Data

Working with Spring Data Neo4j (using simple mapping mode), I occasionally come across NotInTransactionException's being thrown inside methods that are annotated with #Transactional, and have found myself pulling out more hairs than I can afford to lose trying to diagnose these exceptions. For example, the following method:
#Service
public class FooService {
#Autowired Neo4jTemplate template;
//GraphPersisted is an interface containing a single method: Long getId()
//ModelNode is an empty interface implemented by my #NodeEntity classes
#Transactional
public <T extends ModelNode> T getNode(GraphPersisted g, Class<T> clazz){
return template.repositoryFor(clazz).findOne(g.getId()); //NotInTransactionException!!
}
}
is throwing the following:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: nested exception is org.neo4j.graphdb.NotInTransactionException
at org.springframework.data.neo4j.support.Neo4jExceptionTranslator.translateExceptionIfPossible(Neo4jExceptionTranslator.java:51)
at org.springframework.data.neo4j.support.Neo4jTemplate.translateExceptionIfPossible(Neo4jTemplate.java:447)
at org.springframework.data.neo4j.support.Neo4jTemplate.getNode(Neo4jTemplate.java:481)
at org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl.getById(NodeGraphRepositoryImpl.java:33)
at org.springframework.data.neo4j.repository.NodeGraphRepositoryImpl.getById(NodeGraphRepositoryImpl.java:24)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.findOne(AbstractGraphRepository.java:127)
at org.springframework.data.neo4j.repository.AbstractGraphRepository.findOne(AbstractGraphRepository.java:51)
at net.mypkg.myapp.core.FooService.getNode(FooService.java:28)
at net.mypkg.myapp.citizenry.BarService.getCitNode(BarService.java:136)
at net.mypkg.myapp.citizenry.BarService.loadCitizens(BarService.java:81)
at net.mypkg.myapp.citizenry.BarService$$FastClassBySpringCGLIB$$792b7a4e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
at net.mypkg.myapp.citizenry.BarService$$EnhancerBySpringCGLIB$$59949515.loadCitizens(<generated>)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder.makeVotesFor(VotingActivityBuilder.java:46)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder.build(VotingActivityBuilder.java:35)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder$$FastClassBySpringCGLIB$$6871225a.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
at net.mypkg.myapp.creator.builders.VotingActivityBuilder$$EnhancerBySpringCGLIB$$7f5827a1.build(<generated>)
at net.mypkg.myapp.creator.Creator.create(Creator.java:33)
at net.mypkg.myapp.creator.CreatorDriver.run(CreatorDriver.java:52)
at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:634)
... 5 more
My most immediate question is: Why is this exception being thrown? Why is my #Transactional annotation not doing what I expect it to do (namely wrapping my call to template.findOne(Long id) in a transaction)?
My larger question is: How do you know? What clues are given in the stack trace that might indicate from whence the unexpected behavior is arising? I'm relatively new to Spring and Spring Data, and I'm sure these issues aren't inherently difficult to diagnose, I'm just struggling to do so because I don't know how to interpret the stack trace: What should I be looking for in the trace to diagnose these problems when they arise?
(Please let me know what further code/config is necessary to answer this question and I'll post it - I've purposely included as little as possible, in hopes that what you need to see to diagnose this specific issue will help me understand what I need to be looking at to diagnose similar exceptions in the future. I will say, though, that #Transactional annotations are working as expected for a large number of other methods in the same application context)
To wrap some thoughts up in an answer: Spring (any recent version) establishes transactions by instantiating proxies for objects containing a method annotated with "#Transactional". These proxies (wrapping the original functionality with enter- / exit-code handling a transaction) are generated in one of two ways:
1) via CGLIB by dynamically generating Java byte code for the subclass of the proxy target overriding the annotated method, using an instance of this subclass plus using an instance of the original class
2) via Java Dynamic Proxies mimicing the targeted class by dynamically generating an object implementing all the interfaces of the proxy target plus using an instance of the original class
Spring tries to go with 2) unless explicitly otherwise told. As 2) doesn't work if the target class doesn't implement any interfaces option 1) has to be chosen. Falling back to option 1) may break, too. Think about final methods (as Maarten mentioned) or method with a stricter scope than public.
These general things are all documented in the Spring reference (look for "cglib", "proxy", "transaction", ...).
Coming back to your example (hoping its not accidentally oversimplified):
a) the class FooService containing the annoted method getNode does not implement any interface (by the way this is really a bad practice; you ought to program against an interface, e.g. easily allowing you to exchange the implementation), Spring has to go the "CGLIB way". Using CGLIB should work, as nothing is final, the annotated method is public, calling the base class constructor twice doesn't do any harm, ...
b) calling from the stacktrace we can tell that the classes BarService and VotingActivityBuilder are proxied using CGLIB, so generally this does work.
c) if the mentioned BarService and VotingActivityBuilder are proxied because of an #Transactional annotation, you've successfully setup an transaction manager and enabled annotation driven transactions (via <tx:annotation-driven/> or #EnableTransactionManagement). Though I fear these two objects are proxied for other reasons (tell us! :-)). In the latter case instantiate a transaction manager and enable annotation driven transactions (cf. Maarten's answer).
d) lets exclude the case of multiple tx managers (you only have one, don't you?)
e) looking at the stacktrace we can exclude the case of internally calling setNode (i.e. calling it from another, not tx aware method of FooService). Doing so would bypass the proxied version of the annotated method.
f) last thing I can imagine for now (but can't tell from the stacktrace or your provided code for sure), is your code having more than one ApplicationContext (e.g. Web-Apps usually have a "root context" as well as a "dispatcher context" having a parent-child relation). If you instantiate FooService as part of a parent context and put #EnableTransactionManagement at your child context, then no tx logic will be generated.
I'd go for c) or f).
PS: A stacktrace of a proxied FooService throwing an exception in a tx annotated method setNode looks on my machine like
java.lang.IllegalArgumentException: This is for testing purposes.
at eu.example.service.FooService.getNode(FooService.java:94)
at eu.example.service.FooService$$FastClassByCGLIB$$837ba2c0.invoke(<generated>)
at o.s.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at o.s.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
at o.s.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at o.s.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at o.s.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at o.s.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at o.s.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at o.s.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at eu.example.service.FooService$$EnhancerByCGLIB$$e1fb8939.getNode(<generated>)
Judging from the stacktrace, an instance of BarService is making a call to a non proxied instance of FooService. If the latter where proxies, you would see CGLibEnhance-ed classes in the stacktrace and -IIRC- in your case also the TransactionInterceptor that is responsible for starting the transaction.
Now as to why the instance is not proxied, that is hard to say. Is #EnableTransactionManagement missing? Is the instance not managed by Spring? Can the class not be proxied because it is final?

Spring Propagation.REQUIRES_NEW

In my understanding newPrint method in the following code should create a new transaction but apparently it prints out the same transaction-status object as was used in oldPrint method. I am calling oldPrint from another class. Is it because newPrint is being called using this? If yes, then when will a new transaction get created? If I call both methods from another class two separate transaction will be created anyway because #Transactional is used at class level.
#Transactional
public class Unsubcriber {
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void newPrint() {
System.out.println(TransactionAspectSupport.currentTransactionStatus());
}
public void oldPrint() {
System.out.println(TransactionAspectSupport.currentTransactionStatus());
newPrint();
}
Output:
org.springframework.transaction.support.DefaultTransactionStatus#3bacd0e7
org.springframework.transaction.support.DefaultTransactionStatus#3bacd0e7
What would be the scenario when Propagation.REQUIRES_NEW would work?
Assuming geoand's edit clarification is true, the answer to your question is Spring uses AOP proxies to apply the transaction restrictions. So, this will work when calls come into you Unsubscriber from outside, which can then be intercepted and the transaction boundaries can be applied. If you're calling it from within your class, as you said, using 'this', then there is no proxying that can be done and hence your #Transactional will not come into play.
Here are few rules of #Transactional worth mentioning
1.#Transactional annotations only work on public methods. If you have a private or protected method with this annotation there’s no (easy)
way for Spring AOP to see the annotation. It doesn’t go crazy trying
to find them so make sure all of your annotated methods are public.
2.Transaction boundaries are only created when properly annotated (see above) methods are called through a Spring proxy. This means that
you need to call your annotated method directly through an #Autowired
bean or the transaction will never start. If you call a method on an
#Autowired bean that isn’t annotated which itself calls a public
method that is annotated YOUR ANNOTATION IS IGNORED. This is because
Spring AOP is only checking annotations when it first enters the
#Autowired code.
Source - http://blog.timmattison.com/archives/2012/04/19/tips-for-debugging-springs-transactional-annotation/
What you are seeing is a class misconception about Spring AOP.
Since newPrint() is being called from a method inside the same class, no advice is triggered and therefor no handling for transactional takes place.
Had you called the method newPrint() outside the class, a new transaction would be created whether or not the caller already participated in a transaction.
Since you have used #Transactional on the class, every method get's the default #Transactional settings and that is why you actually have a transaction.
Take a look at this section of the Spring reference documentation for a detailed discussion on how AOP works in Spring.
A total hack to get your code working like you expect would be the following:
((Unsubcriber ) AopContext.currentProxy()).newPrint();
This solution is mentioned in various places among which is this SO post.
Calling a method from within a class (using this) means that it will not go through the transaction initialisation contained within Spring's proxy object. Since the this keyword is a pointer to an instance of your original object, not the transaction aware, enhanced Spring object.
The annotations will work as expected in scenarios such as:
object1.oldPrint();
object1.newPrint();

EJB Transaction - static context - bad idea?

The Situation
Imagine the following:
There is an enum like this:
enum State{
INITIAL{
#Override
public void proceed(){...}
},
NEXT_STATE{
#Override
public void proceed(){ ... }
},
//and so on
TERMINATED;
public void proceed(){}
}
Then there's an #Entity. This entity represents a usesase in an application which processes orders. Let's call it ActivationUseCase. ActivationUseCase (like any other class inheriting from my UseCase base class) has an attribute called state which contains a State.
And the last piece of the putzzle is an EJB 3.1 bean which retrieves an ActivationUseCase and calls proceed() on it.
The idea is to let the #Entity hold all information about it's possible states (the enum) and each state knows what to do when it has to .proceed().
The Problem
inside the proceed() method we have a static context. But we might want to call other EJBs. So someone started do do JNDI lookups (local) and call the beans we need.
IMHO that's quite ugly and dangerous, but that's not the question here.
Just to be clear, here's a stack of pseudo-calls:
MyServiceBean.myServiceMethod()
|- ActivationUseCase.proceed()
|- ManuallyLookedUpEJB.anotherServiceMethod()
So MyServiceBean.myServiceMethod() starts a Transaction, retrieves the ActivationUseCase instance to call proceed() on it. Then we lookup ManuallyLookedUpEJB (new InitialContext()...) and call anotherServiceMethod().
The Question
What happens to the Transaction? Where does it start? Will it cover anotherServiceMethod()? How i can i debug this?
Disclaimer
I don't want to discuss the enum-contains-logic construct (now). In fact i'm gathering reasons for refactoring (rewriting) the whole thing. I just need some reasons to support my claim that this construct is not a good idea.
The transaction will propagate like with any other method call. So, unless ManuallyLookedUpEJB.anotherServiceMethod() has a REQUIRES_NEW transaction propagation, it will execute in the same transaction as the one started by MyServiceBean.myServiceMethod().

Specifying the order of proxy creation in Spring

I have a Spring Application where I have the following skeleton class
class ServiceCaller
{
public Result callService()
{
//call a remote service
}
}
Since calling a remote service is an expensive operation, I added caching in my application. I used EhCache Spring annotations #Cacheable and applied it to the callService() method. Everything was working fine and my Result objects were getting correctly cached.
Later I wanted to add a logger across all my ServiceCallers such that my logger would record every actual call to a remote service. I did not want to manually add logger.info() to every such callService method so I decided to use a Spring AOP to implement this.
I defined a pointcut after-returning to all the methods that I wanted to log. It was working; however I noticed that my logger point cut was invoked even when I had a cache hit and my actual callService method was not called. This, I observed, was happening because the order of my proxy to the ServiceCaller bean was as follows: AOPPointCutProxy(EhCacheCachingProxy(ServiceCallerBean)). I want my logger pointcut to be invoked only when my actual callService method is called and not when it is returning with a cached value from the EhCache proxy. Which means that I actually want my proxy creation hierarchy to be in the form of EhCacheCachingProxy(AOPPointCutProxy(ServiceCallerBean)). Note that my bean definitions, pointcut definitions, cache configs may all be in different randomly named xml files.
So how do I enforce Spring to create the proxies in the order I want?
That is what the Ordered interface is used for. You need to implement that on your beans.
You can create a proxy that gets all of the proxies injected that should surround you call. Only that composite proxy surrounds the actual bean. Upon invocation it calls the injected proxies in their specified order.

#Asynchronous private method in EJB

I have an asynchronous method in my EJB singleton that's called from another method in the same class. I already know that I can't call the asynchronous method directly, I have to obtain an EJB proxy. The problem is, I don't want the asynchronous method to be visible outside the class; but when I make it private, it's not executed asynchronously. (I'm using Glassfish v3.)
The javadocs don't say anything about the required access level. So should this be considered a bug in Glassfish?
method annotation cannot be used in private methods. When Glassfish is compiling your EJB it will basically convert your annotation into a piece of code that will surround your code in a proxy. If your method is private it will bypass the proxy Glassfish created... So, in your case I suggest to create a new EJB with your asynchronous method in inject it in your current EJB
That's a very interesting bit of feedback. I can see the value in what you are trying to do. Try marking your bean as an #LocalBean and annotating your #Asynchronous method as protected.
As #LocalBean support is basically done via subclassing the bean class (dynamically or statically), it isn't really possible for the container to override the private method. But I can certainly see your use case. If the protected method approach doesn't work, we can probably add this as an enhancement to EJB.next.
Would still give access to other beans in the same package, but it's at least less public. I've often wished Java had an 'only subclasses' scope. I've almost never used protected and thought, "great, now everyone in my package can access this too."

Categories

Resources