Diagnosing transactional exceptions in Spring Data - java

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?

Related

How to understand annotation in java And How to implement my annotation in java?

What I have known are:
annotation was added in java 5
annotation can be using in method, class, and property
annotation can work in RUNTIME, CLASS, SOURCE( I don't know how to work with CLASS and SOURCE, and their's features)
annotation with retention which is RUNTIME can be implement when java program is running.
And I want to implement a annotation to have follows features:
ensure class only being allowed to create a instance
ensure methods only being allowed to access method in the class
it is like as friend in c++
it is same as public and private , but more dynamicall, like
#MyAnnotation(allowMethods={xxx.doSomething})
public void getValue(){}
the getValues method only can be accessed in the instance self and xxx.doSomething() method
What should I do and learn in next?
And Where can I learn about these?
I think you might be misunderstanding something there. Annotations are descriptive elements, not parts of your program. You can write as many annotations as you want, and people who use your code will still be able to ignore them.
That said, an annotation that enforces a policy (as yours does) can actually be implemented, either at compile or at runtime, but you need an external mechanism to help you. I can think of 3:
Annotation processing lets you interact with the compiler and process annotations by generating code or by omitting compiler errors. Unfortunately, I don't think it will work for your case, as you want to protect your annotated type from instantiation, and that means the call site doesn't actually have an annotation. Annotation processing only gives you access to the actual code pieces that have annotations, not to those that refer to them.
AspectJ allows you to write policy enforcement aspects and omit compiler errors, based on static pointcuts. The problem here is that static pointcuts have very limited semantics, so while you could forbid the instantiation of your class altogether, or from certain packages, you could not limit the your class instantiations to 1.
The third way, and probably the only sane way is that you use a container like Spring or Guice and configure your class as singleton. As long as you only retrieve your class from the container, it will never create a second instance.
Finally: If you want to limit the number of instantiations of your class, you can always use a classic Singleton pattern approach.

Why is Spring's ApplicationContext.getBean with Interface considered bad? [duplicate]

I asked a general Spring question: Auto-cast Spring Beans and had multiple people respond that calling Spring's ApplicationContext.getBean() should be avoided as much as possible. Why is that?
How else should I gain access to the beans I configured Spring to create?
I'm using Spring in a non-web application and had planned on accessing a shared ApplicationContext object as described by LiorH.
Amendment
I accept the answer below, but here's an alternate take by Martin Fowler who discusses the merits of Dependency Injection vs. using a Service Locator (which is essentially the same as calling a wrapped ApplicationContext.getBean()).
In part, Fowler states, "With service locator the application class asks for it [the service] explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.
Inversion of control is a common feature of frameworks, but it's something that comes at a price. It tends to be hard to understand and leads to problems when you are trying to debug. So on the whole I prefer to avoid it [Inversion of Control] unless I need it. This isn't to say it's a bad thing, just that I think it needs to justify itself over the more straightforward alternative."
I mentioned this in a comment on the other question, but the whole idea of Inversion of Control is to have none of your classes know or care how they get the objects they depend on. This makes it easy to change what type of implementation of a given dependency you use at any time. It also makes the classes easy to test, as you can provide mock implementations of dependencies. Finally, it makes the classes simpler and more focused on their core responsibility.
Calling ApplicationContext.getBean() is not Inversion of Control! While it's still easy to change what implemenation is configured for the given bean name, the class now relies directly on Spring to provide that dependency and can't get it any other way. You can't just make your own mock implementation in a test class and pass that to it yourself. This basically defeats Spring's purpose as a dependency injection container.
Everywhere you want to say:
MyClass myClass = applicationContext.getBean("myClass");
you should instead, for example, declare a method:
public void setMyClass(MyClass myClass) {
this.myClass = myClass;
}
And then in your configuration:
<bean id="myClass" class="MyClass">...</bean>
<bean id="myOtherClass" class="MyOtherClass">
<property name="myClass" ref="myClass"/>
</bean>
Spring will then automatically inject myClass into myOtherClass.
Declare everything in this way, and at the root of it all have something like:
<bean id="myApplication" class="MyApplication">
<property name="myCentralClass" ref="myCentralClass"/>
<property name="myOtherCentralClass" ref="myOtherCentralClass"/>
</bean>
MyApplication is the most central class, and depends at least indirectly on every other service in your program. When bootstrapping, in your main method, you can call applicationContext.getBean("myApplication") but you should not need to call getBean() anywhere else!
Reasons to prefer Service Locator over Inversion of Control (IoC) are:
Service Locator is much, much easier for other people to following in your code. IoC is 'magic' but maintenance programmers must understand your convoluted Spring configurations and all the myriad of locations to figure out how you wired your objects.
IoC is terrible for debugging configuration problems. In certain classes of applications the application will not start when misconfigured and you may not get a chance to step through what is going on with a debugger.
IoC is primarily XML based (Annotations improve things but there is still a lot of XML out there). That means developers can't work on your program unless they know all the magic tags defined by Spring. It is not good enough to know Java anymore. This hinders less experience programmers (ie. it is actually poor design to use a more complicated solution when a simpler solution, such as Service Locator, will fulfill the same requirements). Plus, support for diagnosing XML problems is far weaker than support for Java problems.
Dependency injection is more suited to larger programs. Most of the time the additional complexity is not worth it.
Often Spring is used in case you "might want to change the implementation later". There are other ways of achieving this without the complexity of Spring IoC.
For web applications (Java EE WARs) the Spring context is effectively bound at compile time (unless you want operators to grub around the context in the exploded war). You can make Spring use property files, but with servlets property files will need to be at a pre-determined location, which means you can't deploy multiple servlets of the same time on the same box. You can use Spring with JNDI to change properties at servlet startup time, but if you are using JNDI for administrator-modifiable parameters the need for Spring itself lessens (since JNDI is effectively a Service Locator).
With Spring you can lose program Control if Spring is dispatching to your methods. This is convenient and works for many types of applications, but not all. You may need to control program flow when you need to create tasks (threads etc) during initialization or need modifiable resources that Spring didn't know about when the content was bound to your WAR.
Spring is very good for transaction management and has some advantages. It is just that IoC can be over-engineering in many situations and introduce unwarranted complexity for maintainers. Do not automatically use IoC without thinking of ways of not using it first.
It's true that including the class in application-context.xml avoids the need to use getBean. However, even that is actually unnecessary. If you are writing a standalone application and you DON'T want to include your driver class in application-context.xml, you can use the following code to have Spring autowire the driver's dependencies:
public class AutowireThisDriver {
private MySpringBean mySpringBean;
public static void main(String[] args) {
AutowireThisDriver atd = new AutowireThisDriver(); //get instance
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"/WEB-INF/applicationContext.xml"); //get Spring context
//the magic: auto-wire the instance with all its dependencies:
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(atd,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
// code that uses mySpringBean ...
mySpringBean.doStuff() // no need to instantiate - thanks to Spring
}
public void setMySpringBean(MySpringBean bean) {
this.mySpringBean = bean;
}
}
I've needed to do this a couple of times when I have some sort of standalone class that needs to use some aspect of my app (eg for testing) but I don't want to include it in application-context because it is not actually part of the app. Note also that this avoids the need to look up the bean using a String name, which I've always thought was ugly.
One of the coolest benefits of using something like Spring is that you don't have to wire your objects together. Zeus's head splits open and your classes appear, fully formed with all of their dependencies created and wired-in, as needed. It's magical and fantastic.
The more you say ClassINeed classINeed = (ClassINeed)ApplicationContext.getBean("classINeed");, the less magic you're getting. Less code is almost always better. If your class really needed a ClassINeed bean, why didn't you just wire it in?
That said, something obviously needs to create the first object. There's nothing wrong with your main method acquiring a bean or two via getBean(), but you should avoid it because whenever you're using it, you're not really using all of the magic of Spring.
The motivation is to write code that doesn't depend explicitly on Spring. That way, if you choose to switch containers, you don't have to rewrite any code.
Think of the container as something is invisible to your code, magically providing for its needs, without being asked.
Dependency injection is a counterpoint to the "service locator" pattern. If you are going to lookup dependencies by name, you might as well get rid of the DI container and use something like JNDI.
Using #Autowired or ApplicationContext.getBean() is really the same thing. In both ways you get the bean that is configured in your context and in both ways your code depends on spring.
The only thing you should avoid is instantiating your ApplicationContext. Do this only once! In other words, a line like
ApplicationContext context = new ClassPathXmlApplicationContext("AppContext.xml");
should only be used once in your application.
One of Spring premises is avoid coupling. Define and use Interfaces, DI, AOP and avoid using ApplicationContext.getBean() :-)
One of the reasons is testability. Say you have this class:
interface HttpLoader {
String load(String url);
}
interface StringOutput {
void print(String txt);
}
#Component
class MyBean {
#Autowired
MyBean(HttpLoader loader, StringOutput out) {
out.print(loader.load("http://stackoverflow.com"));
}
}
How can you test this bean? E.g. like this:
class MyBeanTest {
public void creatingMyBean_writesStackoverflowPageToOutput() {
// setup
String stackOverflowHtml = "dummy";
StringBuilder result = new StringBuilder();
// execution
new MyBean(Collections.singletonMap("https://stackoverflow.com", stackOverflowHtml)::get, result::append);
// evaluation
assertEquals(result.toString(), stackOverflowHtml);
}
}
Easy, right?
While you still depend on Spring (due to the annotations) you can remove you dependency on spring without changing any code (only the annotation definitions) and the test developer does not need to know anything about how spring works (maybe he should anyway, but it allows to review and test the code separately from what spring does).
It is still possible to do the same when using the ApplicationContext. However then you need to mock ApplicationContext which is a huge interface. You either need a dummy implementation or you can use a mocking framework such as Mockito:
#Component
class MyBean {
#Autowired
MyBean(ApplicationContext context) {
HttpLoader loader = context.getBean(HttpLoader.class);
StringOutput out = context.getBean(StringOutput.class);
out.print(loader.load("http://stackoverflow.com"));
}
}
class MyBeanTest {
public void creatingMyBean_writesStackoverflowPageToOutput() {
// setup
String stackOverflowHtml = "dummy";
StringBuilder result = new StringBuilder();
ApplicationContext context = Mockito.mock(ApplicationContext.class);
Mockito.when(context.getBean(HttpLoader.class))
.thenReturn(Collections.singletonMap("https://stackoverflow.com", stackOverflowHtml)::get);
Mockito.when(context.getBean(StringOutput.class)).thenReturn(result::append);
// execution
new MyBean(context);
// evaluation
assertEquals(result.toString(), stackOverflowHtml);
}
}
This is quite a possibility, but I think most people would agree that the first option is more elegant and makes the test simpler.
The only option that is really a problem is this one:
#Component
class MyBean {
#Autowired
MyBean(StringOutput out) {
out.print(new HttpLoader().load("http://stackoverflow.com"));
}
}
Testing this requires huge efforts or your bean is going to attempt to connect to stackoverflow on each test. And as soon as you have a network failure (or the admins at stackoverflow block you due to excessive access rate) you will have randomly failing tests.
So as a conclusion I would not say that using the ApplicationContext directly is automatically wrong and should be avoided at all costs. However if there are better options (and there are in most cases), then use the better options.
The idea is that you rely on dependency injection (inversion of control, or IoC). That is, your components are configured with the components they need. These dependencies are injected (via the constructor or setters) - you don't get then yourself.
ApplicationContext.getBean() requires you to name a bean explicitly within your component. Instead, by using IoC, your configuration can determine what component will be used.
This allows you to rewire your application with different component implementations easily, or configure objects for testing in a straightforward fashion by providing mocked variants (e.g. a mocked DAO so you don't hit a database during testing)
Others have pointed to the general problem (and are valid answers), but I'll just offer one additional comment: it's not that you should NEVER do it, but rather that do it as little as possible.
Usually this means that it is done exactly once: during bootstrapping. And then it's just to access the "root" bean, through which other dependencies can be resolved. This can be reusable code, like base servlet (if developing web apps).
There is another time when using getBean makes sense. If you're reconfiguring a system that already exists, where the dependencies are not explicitly called out in spring context files. You can start the process by putting in calls to getBean, so that you don't have to wire it all up at once. This way you can slowly build up your spring configuration putting each piece in place over time and getting the bits lined up properly. The calls to getBean will eventually be replaced, but as you understand the structure of the code, or lack there of, you can start the process of wiring more and more beans and using fewer and fewer calls to getBean.
I've only found two situations where getBean() was required:
Others have mentioned using getBean() in main() to fetch the "main" bean for a standalone program.
Another use I have made of getBean() are in situations where an interactive user configuration determines the bean makeup for a particular situation. So that, for instance, part of the boot system loops through a database table using getBean() with a scope='prototype' bean definition and then setting additional properties. Presumably, there is a UI that adjusts the database table that would be friendlier than attempting to (re)write the application context XML.
however, there are still cases where you need the service locator pattern.
for example, i have a controller bean, this controller might have some default service beans, which can be dependency injected by configuration.
while there could also be many additional or new services this controller can invoke now or later, which then need the service locator to retrieve the service beans.
You should to use: ConfigurableApplicationContext instead of for ApplicationContext

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();

Are all methods proxied when using Spring AOP?

When using Spring AOP to create a proxy for a class using NameMatchMethodPointcutAdvisor and BeanNameAutoProxyCreator does this essentially proxy every call to the object, but only apply the advice to the matched methods, or somehow create a Proxied object that only has those methods and uses the normal object for the calls that are supposed to be intercepted?
The way, I think I understand it is that it does proxy every call to the object but then only calls the Advisor on the methods that match - but I can't find a good example/post to confirm this.
Depends on the technique used. (It is configurable by an attribute proxy-target-class in your aop config)
JDK dynamic proxies are proxies by interface - each methods of the interface goes through the proxy, as you said, and if it matches happens to be an "advised" method, the advisor is applied. Otherwise it is delegated to the original object
CGLIB proxies are effectively subclasses defined at runtime of your concrete classes. I can't be sure in this, but I assume only the "advised" methods are overridden, the rest retain the definition of the superclass.
However, no matter which mechanism is used:
it isn't your concern how exactly are the proxies implemented
this doesn't impact performance in a significant way - Debunking myths: proxies impact performance by the Spring team about proxy performance myths
or somehow create a Proxied object that only has those methods and uses the normal object for the calls that are supposed to be intercepted?
How would this actually work? When a class has a reference to the class that is being proxied, it only has one reference to it. It either has to invoke a proxy class or a non-proxied class. Spring can't know which methods you are calling and therefore can't give you one type if you need to call the advised method and another type if you're not.

Spring - #Transactional - What happens in background?

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.

Categories

Resources