Hot questions for Using AspectJ in transactions

Top Java Programmings / AspectJ / transactions

Question:

I'm having a problem with a combination of @EnableLoadTimeWeaving with AspectJ + @Transactional + @HystrixCommand.

So, I've configured load-time weaving like this:

@EnableLoadTimeWeaving(aspectjWeaving = ENABLED)
@EnableCaching(mode = AdviceMode.ASPECTJ)
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)

plus instrumentation configuration.

I have a bean A, annotated with @Transactional and method in it, annotated with @HystrixCommand.

Then I have a bean B, also annotated with @Transactional, but having propagation = Propagation.MANDATORY, which means that it requires existing transaction and fails otherwise. There's also a method in this bean, annotated with @HystrixCommand.

Eventually, when I call the method of bean B from the method of bean A, I get: No existing transaction found for transaction marked with propagation 'mandatory'.

I was looking for the problem for a couple of hours: everything seems to be configured properly, so I almost gave up. And then I just tried to remove @HystrixCommand from methods. And voilĂ : transaction propagation started to work properly and the exception was gone.

So I wonder: why does @HystrixCommand break transaction propagation? Is it somehow related to the fact that I'm using load-time weaving? Or is it expected behaviour? Can someone shed some light on it?


Answer:

The problem you're stating is probably related to the fact that HystrixCommands are executed in an isolated thread:

The default, and the recommended setting, is to run HystrixCommands using thread isolation (THREAD) and HystrixObservableCommands using semaphore isolation (SEMAPHORE).

Commands executed in threads have an extra layer of protection against latencies beyond what network timeouts can offer.

Generally the only time you should use semaphore isolation for HystrixCommands is when the call is so high volume (hundreds per second, per instance) that the overhead of separate threads is too high; this typically only applies to non-network calls.

Question:

Is there a way to trace transactions end to end over distributed applications system using Spring AOP or AspectJ, without changing the existing codes? The web service interactions between applications may be RMI, SOAP or REST? I am looking for a general approach and just want to know if it possible using Spring AOP and AspectJ.


Answer:

Yes, it is possible with AspectJ, but there is no easy "cooking recipe" or "template for dummies". You need a custom solution. In order to concretely answer your question I would have to see your code. Another guy from India lately asked me the same, maybe he works on the same project as you.

The general approach is to transfer state between client and server by injecting a unique parameter (something like a transaction ID) into the request and using it on the server. Both client and server should be aspect-enabled. This should be possible via RMI, SOAP and REST, provided you find a place where to inject an additional parameter. In RMI and SOAP this could be an existing general-purpose key-value dictionary for optional parameters, in REST it could be a header field or a request parameter.

Question:

I have an aspect-j aspect (weaved at compile time) to log method name and execution time when this last is greater than 1s.

Logs are aggregated in an ELK stack and we would like to make profiling visualisation, the problem is all the subcall in the stack are also traced and we have so multiple traces with multiple method name for each unit of work.

I would like to trace only the entry point method of each unit of work ie. each method triggering a new transaction (and not the one joining an existing transaction).

Is there a way to do so without overriding spring TransactionInterceptor ?


Answer:

If you need a simple solution using only AspectJ, the following might work for you.

Let's say you have a named pointcut transactionalMethodExecution:

pointcut transactionalMethodExecution(): execution(@org.springframework.transaction.annotation.Transactional * *(..));;

You can exclude all nested transactionalMethodExecution pointcuts in the control flow of the topmost one by using cflowbelow:

transactionalMethodExecution() && !cflowbelow(transactionalMethodExecution())

From the documentation on cflowbelow:

cflowbelow(Pointcut)

Picks out each join point in the control flow of any join point P picked out by Pointcut, but not P itself.

This solution is admittedly simplistic, it doesn't handle cases like nested transactions or anything more fancy. You'll need a more thorough solution for those cases.

Question:

I have Spring aspect

@Aspect
@Component
public class SomeAspect

with @Around advice for service method

@Around("execution(* some.pack.SomeService.someMethod(..))")
    public Object triggerSome(ProceedingJoinPoint pjp) throws Throwable {
        //pre-processing
        Object res = pjp.proceed();
        additionalService.additionalAction();
        return res;
    }

All methods (SomeService.someMethod and AdditionalService.additionalAction) are @Transactional methods. I search a solution to execute this methods in one transaction. When [aditionalAction] method is fail changes added by [someMethod] must be rollbacked.

Adding the @Transactional annotation to the advice method is not working. Using of @Order annotation for configure transaction manager and aspects does not give that I need.

Is it possible to invoking this methods in one transaction?


Answer:

Add a third Method on your Service and Mark it as @Transactional.

@Transactional
Object thirdMethod(){
   Object res = pjp.proceed();
   additionalService.additionalAction();
   return res;
}

and call it from your Aspect:

    @Around("execution(* some.pack.SomeService.someMethod(..))")
    public Object triggerSome(ProceedingJoinPoint pjp) throws Throwable {
        //pre-processing
        return thirdMethod();
    }