0

I have below Java code which intercepts the method getUserDetails() using Spring AOP and logs its execution time. The method calculateExecutionTime gets executed in the same thread as getUserDetails().

package com.poc.app.data;

import org.springframework.stereotype.Repository;

@Repository
public class User {
    public String getUserDetails() {
        return "user details";
    }
}
package com.poc.app.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;

@Aspect
@Configuration
public class ExecutionTimeAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Around("execution(* com.poc.app..*.*(..))")
    public Object calculateExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object returnValue = joinPoint.proceed();
        long timeTaken = System.currentTimeMillis() - startTime;
        logger.info("Time taken by {} to complete execution is: {}", joinPoint, timeTaken);
        return returnValue;
    }
}

Question: I am working on creating another Aspect to capture runtime data of various methods (like the input parameter values, the return values) using @Before and @After Spring AOP advices.

  1. Is it possible to run those advices in a separate thread then the one running the actual methods say getUserDetails in this example?
  2. Is it possible to create a custom advice types similar to @Before and @After and have them run in separate thread then the method being intercepted?
kriegaex
  • 63,017
  • 15
  • 111
  • 202
user762421
  • 503
  • 1
  • 12
  • 24
  • Instead of adding complexity with a threadpool I would first start with implementing it without and see if this really is an issue (it rarely is in my experience). Also to apply metrics on method excution there are already various solution out there which integrate with Spring (like Micrometer for instance). – M. Deinum Jul 05 '23 at 11:07
  • The accepted answer involves a lot of manual work. Simply use `@Async`, but please note the caveats I explained in my answer to the question I marked this one as a duplicate of. Please also note my thoughts about whether you ought to use asynchronous advice at all. That it is possible, does not necessarily mean that it ought to be used unless strictly necessary. P.S.: Your second try to ask this question is certainly better than the [first one](https://stackoverflow.com/q/76603831/1082681). – kriegaex Jul 08 '23 at 08:29

1 Answers1

0

I don't think that its a responsibility of AOP framework to provide multi threaded execution. The business code gets wrapped by advices and basically you can run the code in advice before the business code, after the business code or around the business code (by possibly omitting the business code execution).

Having said that, there is nothing that stops you to spawn a thread (or in a more realistic scenario, probably, using a thread from thread pool) from within an advice and "offload" the potentially expensive execution to that thread.

Of course it will be the responsibility of the programmer to handle possible errors that might arise during the code execution (both the aspect's code and the business code itself).

This probably answers also your second question: you should be ok with these 3 types , no need to create additional types for that.

In a pseudo code it looks like this:

@Aspect
@Configuration
public class ExecutionTimeAspect {

    private ThreadPool theadPool = ... // you can user executors of java, maybe queues for async task execution and so on, I name it 'generic thread pool' here, which is technology agnostic

    @Around("execution(* com.poc.app..*.*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        threadPool.execute(this::executeExpensiveOperation); // this is off-loaded to another thread actually 
        return joinPoint.proceed();
    }

    private void executeExpensiveOperation() {
       // this should be run in a separate thread 
    }
}
Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97