Spring transaction creation - spring

This question was asked me in one interview
class A{
#Transactional
public void test1(){
test2();
}
#Transactional(propagation = REQUIRED.NEW)
public void test2(){}
}
class B extends A{
public void test1(){
super.test1();
}
}
He asked me how many transaction objects would be created? The answer was 1, not 2. now I am having a hard time struggling with this part. He said this is how CgLib proxy works, can anyone explain this part?

This program can be rewritten like:
class A{
#Transactional
public void test1(){
this.test2(); // this is added
}
#Transactional(propagation = REQUIRED.NEW)
public void test2(){}
class B extends A{
public void test1(){
super.test1();
}
suppose you get A from application context and call the test1() method on that:
var a = context.getBean(A.class);
a.test1()
we know that a is actually the proxy object so a transaction is going to be created. in test1() method we call this.test2() method.
From Spring doc:
However, once the call has finally reached the target object any
method calls that it may make on itself, such as this.bar() or
this.foo(), are going to be invoked against the this reference, and
not the proxy
so for test2() method no transaction is going to be created because this is invoked against the A class not the proxy class with all transactional stuff support.
Now suppose that you get B from application context and invoke test1() method against it.
var b = context.getBean(B.class);
b.test1()
Because B is the subclass of A and A is annotated with Transactional, B itself is a proxy (#Transactional is automatically inherited even though test1() in B is not annotated with #Transactional). so a transaction is going to be created. when we reach the target object all transaction stuff goes away and no more transaction is going to be created like the first case.

Related

Does Transactional.TxType.REQUIRES_NEW start a new transaction when called from the same bean?

AFAIK
In proxy mode (which is the default), 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!
But here is: Transactional.TxType.REQUIRES_NEW
Will be the second transaction created?
#Service
public class SomeService {
#Transactional
public void doSomeLogic() {
// some logic
doOtherThings();
// some logic
}
#Transactional(Transactional.TxType.REQUIRES_NEW)
private void doOtherThings() {
// some logic
}
To get an answer to this question, you need to know how a proxy works.
When you annotate a method inside a bean, the proxy will wrap that bean with the appropriate logic. This means that if you call that annotated method of your bean, the request will first be sent to the proxy object (named with $), which will then call the bean's method. If this method calls another method of the same bean, it will call it without invoking a proxy which has a logic, e.x., of transaction management.
Example: Here is the code which will be wrapped by proxy and an appropriate diagram of its work.
#Service
public class SomeService {
#Transactional
public void foo() {
// this next method invocation is a direct call on the 'this' reference
bar();
}
#Transactional(Transactional.TxType.REQUIRES_NEW)
public void bar() {
// some logic...
}
}
Source
Hence, the answer is No.
Hope that's a little bit more clear now.

Spring AOP does not run as expected [duplicate]

I have several Aspects coded in my application. All others works except for the following.
Service Interface
package com.enbiso.proj.estudo.system.service;
...
public interface MessageService {
...
Message reply(Message message);
Message send(Message message);
...
}
Service Implementation
package com.enbiso.proj.estudo.system.service.impl;
....
#Service("messageService")
public class MessageServiceImpl implements MessageService {
...
#Override
public Message reply(Message message) {
...
return this.send(message);
}
#Override
public Message send(Message message) {
...
}
}
Aspect
#Aspect
#Component
public class NewMessageAspect {
...
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..))",
returning = "message")
public void perform(Message message){
...
}
}
When I try to execute the send method the debug point is not getting hit in the aspect perform.
UPDATE
I did some investigations and found that this doesn't work, when the send method is invoked from the reply method as below
#Autowire MessageService messageService;
...
messageService.reply(message);
But if I call the method messageService.send(message) it works fine. But as reply method is calling send method internally, shouldn't it also invoke the aspect?
I have no idea what i have done wrong. Please help me.
Thank you jst for clearing the things up. Just for the information purposes for the future developer in SO, I'm posting the full answer to this question
Lets assume that there is a bean from SimplePojo
public class SimplePojo implements Pojo {
public void foo() {
this.bar();
}
public void bar() {
...
}
}
When we call the method foo(), it reinvokes the method bar() inside it. Even thought the method foo() is invoked from the AOP Proxy, the internal invocation of the bar() is not covered by the AOP Proxy.
So eventually this makes, if there are any advices attached to the method bar() to not get invoked
Solution
Use AopContext.currentProxy() to call the method. Unfortunately this couples the logic with AOP.
public void foo() {
((Pojo) AopContext.currentProxy()).bar();
}
Reference:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
You are running into a limitation of Spring AOP on self-invocation. You basically can get around it by using AopContext.currentProxy(), refactor code into different beans, or use full ApsectJ weaving.
See explanation here and workaround(s).
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
I guess the problem is the #args condition.
Spring documentation states the following:
#args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
Therefore the parameter of #args has to be a type expression. So the correct pointcut expression is
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..)) && args(com.enbiso.proj.estudo.system.service.impl.Message")
or simply
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(com.enbiso.proj.estudo.system.service.impl.Message))")
Please adjust the package of Message if it doesn't fit.

Spring - #Transactional with ScheduledExecutorService - What happens in background?

I want to know what actually happens when you annotate a method with #Transactional with ScheduledExecutorService?
Assume that the methodA is called externally. Am I correct in assuming that when methodA is called, someDao.methodDao() joins in a transaction and scheduleMethodB() returns immediately.
Later after 2 seconds, the scheduler calls the methodB(). What would this hold in this case? Would it hold the TransactionProxy and execute methodB in a separate transaction? If not, then how would we able to achieve this.
I am aware that #Transactional is based on proxies so is methodB call a self invocation under scheduler.
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!
public class ServiceABImpl implements ServiceAB {
#Autowired
private ScheduledExecutorService scheduledExecutorService;
#Transactional
public void methodA() {
//do some work in a transaction.
someDao.methodDao();
//schedule a methodB
scheduleMethodB();
}
public void scheduleMethodB() {
scheduledExecutorService.schedule(() -> {
this.methodB();
return "";
},
2,
TimeUnit.SECONDS);
}
#Transactional
public void methodB() {
}
}
Since the class is not annotated with #Transactional, the decision of whether an invoked method participates in the transaction of the parent invokee method depends on whether you annotate the invoked methods also with #Transactional and what propagation level you configure it with I think. So for example
#Transactional(propagation=Propagation.REQUIRED)

Unit testing with Mockito

I am writing unit tests for service layer in my spring application.
Here is my service class
#Service
public class StubRequestService implements RequestService {
#Autowired
private RequestDao requestDao;
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
#Override
public Request getRequest(Long RequestId) {
Request dataRequest = requestDao.find(requestId);
return dataRequest;
}
}
Here is my test class
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" })
public class StubRequestServiceTest {
#Mock
public RequestDao requestDao;
StubRequestService stubRequestService; // How can we Autowire this ?
#org.junit.Before
public void init() {
stubRequestService = new StubRequestService(); // to avoid this
stubRequestService.setRequestDao(dataRequestDao);
// Is it necessary to explicitly set all autowired elements ?
// If I comment/remove above setter then I get nullPointerException
}
#Test
public void testGetRequest() {
Request request = new Request();
request.setPatientCnt("3");
when(requestDao.find(anyLong())).thenReturn(request);
assertEquals(stubRequestService.getRequest(1234L).getPatientCnt(),3);
}
}
Its working fine but I have few questions
How can we Autowire service class in test ? I am using constructor in init() method to create service object.
Do we have to set all Autowire element for service class ? For ex StubRequestService have autowired RequestDao which I need to set explicitly before calling test method otherwise it giveds nullPointerException as requestDao is null in StubRequestService.getRequest method.
Which are the good practices to follow while unit testing Spring service layer ? (If I am doing anything wrong).
Your test is fine. It doesn't even have to have the #ContextConfiguration annotation.
The whole point of dependency injection frameworks like Spring is to be able to unit test services by simply instantiating them, setting mock dependencies, and then call their methods.
You're doing it correctly. You don't need to have a Spring context for such unit tests. That's why they're called unit tests: they test it in isolation of all their actual dependencies, Spring included.
Side note: assuming you're using JUnit, the arguments of the assertXxx method should be swapped. The expected value comes before the actual value. It becomes important when the assertion fails and you have a message like "expecting 6 but was 3" rather than "expecting 3 but was 6".
If you really feel that it will make your tests easier to understand - you can initialize a spring context and fetch all of the objects from there. However, usually it will require creating a separate spring configuration XML file specifically for tests therefore I would not recommend it.
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testApplicationContext.xml");
stubRequestService = (RequestService)applicationContext.getBean("myRequestServiceBean");
(and 3) Basically, I prefer testing each component of my application in total isolation from eachother and that's why I do not recommend what I described in [1].
What that means, is you take a separate logical slice of your application and test only it, while fully mocking up everything it tries to access.
Let's say you have three classes:
//Fetches stuff from some webservice and converts to your app domain POJOs
class DataAccessLayer {
public void setWebservice(Webservice ws) {...};
public MyObject getMyObject() {...};
}
//Formats the domain POJOs and sends them to some kind of outputstream or stuff.
class ViewLayer {
public void setOutputStream(OutputStream os) {...};
public void viewMyObject(MyObject mo) {...};
}
//Main entry point of our MyObject fetch-process-display workflow
class Controller {
public void setDataAccessLayer(DataAccessLayer dal) {...};
public void setViewLayer(ViewLayer vl) {...};
public void showMyObject() {
MyObject mo = dal.getMyObject();
...some processing here maybe...
vl.viewMyObject(mo);
}
}
Now, what tests can we write here?
Test if DataAccessLayer properly converts the object from mocked up WS to our domain object.
Test if ViewLayer properly formats the object given to him and writes it to mocked up output stream.
Test if Controller takes an object from mocked up DataAccessLayer processes it properly and sends it to mocked up ViewLayer.
Or You can use springockito
https://bitbucket.org/kubek2k/springockito/wiki/Home, it will make your tests cleaner

Spring AOP - aspect loop execution

in first and foremost i need to say that I'm new in Spring AOP (well, I'm new in AOP at all).
In my application I have service class which is advised by aspect, unitil this point is everyting fine. Aspect is triggered, everyting works. But I need to call that service method from my aspect, and there is problem. My Aspect is (logicaly) triggered for each call and everyting end on StackOwerflow error.
It is possible to prevent that aspect looping ?
I have idea to create IAspectSandbox interface (or class) and method invocations from class which will implement this interface do not trigger aspects. But I really don't know how to achieve this goal :)
My class schema:
#Service
public class MyService
{
public BarObject update( FooObject item )
{
BarObject barObject = new BarObject();
// save FooObject to database and detect changes against old row
// information about fields, that was changed is in BarObject
return barObject;
}
}
--------------------------------------------------------------------------
#Aspect
public class MyServicePointcut
{
#Pointcut("execution(* cz.package.service.MyService.update(..))")
public void myServiceItemChanged() {}
}
--------------------------------------------------------------------------
#Component
#Aspect
public class PraceZadaniChangeAspect
{
#AutoWire
private MyService myService;
#AfterReturning("cz.package.pointcuts.MyServicePointcut.myServiceItemChanged()", returning = "returnVal")
public void execute( BarObject returnVal )
{
// do something with BarObject ... mostly check changes
// .....
// .....
// at the end I need to save changes
myService.update( returnVal.getFooObject() ); // after this call is this aspect triggered again. I know why, but I don't want to :)
}
}
Answer #1: Calling Advised Method Only (Around Advice)
If you autowire your service back into your aspect, you're still invoking Spring's proxy mechanism, including the AOP aspect that you've applied to your service.
See "Around Advice" in the Spring AOP chapter:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-ataspectj-around-advice
Basically, do something like this:
#AfterReturning("...")
public void execute(ProceedingJoinPoint p, BarObject returnVal)
{
// do something with BarObject
// ...
// call original method with original args
p.proceed(p.getArgs());
}
I am not 100% sure on the code, but proceed() should call the target method directly without invoking the AOP proxy recursively.
Answer #2: Calling Multiple Target Object Methods
If you need to call multiple methods from that service object within your aspect, you'll need access to the unproxied object via getTarget():
#AfterReturning("...")
public void execute(JoinPoint p, BarObject returnVal)
{
// do something with BarObject
// ...
// call various service methods without triggering this AOP proxy again
// by using getTarget() to get the unproxied object:
MyService myService = (MyService) p.getTarget();
myService.update(...); // does not trigger AOP interceptor
myService.otherMethod(...); // neither does this
myService.thirdMethod(...); // nor this
}

Resources