通过AOP和AspectJ统计方法执行时间

Spring Boot: Measure Execution Time using Spring AOP and AspectJ

Photo by Veri Ivanova on Unsplash
In this post, I like to document the steps followed to solve the Concern surrounding logging execution time in a Spring Boot Application using Spring-AOP(Aspect Oriented Programming) and AspectJ.

GitHub: https://github.com/shinemon/demo-spring-boot/tree/master/spring-boot-aop-aspectj

Let’s consider a simple Spring Boot Application with a Controller and Service.

Controller:

@RestController
@Slf4j
@RequestMapping(“/api”)
public class Employee {

@Autowired
private EmployeeService employeeService;

@GetMapping(value = "/get/employee/name/{id}")
public String getEmployeeName(@PathVariable String id){
    if (StringUtils.isBlank(id)){
        return null;
    }
    return employeeService.getEmployeeNameFromId(id);
}

}
Service:

@Service
@Slf4j
public class EmployeeService {

public String getEmployeeNameFromId(String id){
    return "Test Name From Service";
}

}
Aim: Calculate and Log execution time taken by a Method.

Solution (Traditional Me😀 ): find current time in milliseconds prior to method start, and subtract with current time post method execution. May be create a Util, and still we will end up several boiler plater code within our class/methods.

Better Solution:

Spring-AOP & AspectJ: Will help us to modularize our current logging Execution Time taken concern.

There are different Advice per AOP Concepts like Before, After, Around. Here we will make use of Around Advice, which helps to surround a Method Execution (Joint Point — term per AOP i.e. a point during the execution of a program.)

Create: ExecutionTimeAdvice and Around with custom Annotation (say TrackExecutionTime)

ExecutionTimeAdvice:

@Aspect
@Component
@Slf4j
@ConditionalOnExpression(“${aspect.enabled:true}”)
public class ExecutionTimeAdvice {

@Around("@annotation(com.mailshine.springboot.aop.aspectj.advise.TrackExecutionTime)")
public Object executionTime(ProceedingJoinPoint point) throws Throwable {
    long startTime = System.currentTimeMillis();
    Object object = point.proceed();
    long endtime = System.currentTimeMillis();
    log.info("Class Name: "+ point.getSignature().getDeclaringTypeName() +". Method Name: "+ point.getSignature().getName() + ". Time taken for Execution is : " + (endtime-startTime) +"ms");
    return object;
}

}
TrackExecutionTime:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TrackExecutionTime {
}
Now you only need to add “@TrackExecutionTime” annotation to your desired Methods in any of your class.

Adding to our Controller & Service:

@RestController
@Slf4j
@RequestMapping(“/api”)
public class Employee {

@Autowired
private EmployeeService employeeService;

@GetMapping(value = "/get/employee/name/{id}")
@TrackExecutionTime
public String getEmployeeName(@PathVariable String id){
    if (StringUtils.isBlank(id)){
        return null;
    }
    return employeeService.getEmployeeNameFromId(id);
}

}
@Service
@Slf4j
public class EmployeeService {

@TrackExecutionTime
public String getEmployeeNameFromId(String id){
    return "Test Name From Service";
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 这是一个AOP编程的问题,需要使用AspectJ框架来实现。在AspectJ中,可以使用@Before和@After注解来定义前置通知和后置通知,通过计算两个时间点的时间差来统计方法执行时间。同时,可以使用@Pointcut注解来定义切入点,指定需要拦截的方法。最终,将切面类和目标类进行织入,即可实现对所有方法执行时间统计。 ### 回答2: 前后置通知是Spring AOP中的一种通知类型,用于在目标方法执行前或执行后设置额外的行为。通过使用前后置通知,我们可以很容易地统计所有方法执行时间。 在前置通知中,我们可以获取方法执行时间,并将其存储在一个变量中。在后置通知中,我们可以再次获取当前时间,并计算出方法执行时间。最后,我们将所有方法执行时间加在一起,就可以统计出所有方法执行时间了。 下面是一个简单的例子,展示如何使用前后置通知统计所有方法执行时间: ``` @Aspect @Component public class MethodExecutionTimeAspect { private static final Logger LOGGER = LoggerFactory.getLogger(MethodExecutionTimeAspect.class); @Around("execution(* com.example.*.*(..))") public Object logMethodExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = joinPoint.proceed(); long endTime = System.currentTimeMillis(); long elapsedTime = endTime - startTime; LOGGER.debug("Method {} execution time: {} ms", joinPoint.getSignature(), elapsedTime); return result; } } ``` 在上面的代码中,我们定义了一个名为MethodExecutionTimeAspect的切面,并使用@Around注解定义了一个环绕通知。该通知会拦截所有在com.example包下的方法,并在方法执行前记录开始时间,在方法执行后记录结束时间,并计算出执行时间。最后,我们将执行时间记录在日志中,并返回目标方法执行结果。 使用该切面,我们可以很容易地统计所有方法执行时间。只需将其添加到Spring应用程序的配置中即可: ``` @Configuration @EnableAspectJAutoProxy public class AppConfig { @Bean public MethodExecutionTimeAspect methodExecutionTimeAspect() { return new MethodExecutionTimeAspect(); } } ``` 这个简单的例子展示了如何使用前后置通知统计所有方法执行时间。通过使用AOP,我们可以很容易地添加额外的功能来补充应用程序逻辑,并提高代码的可重用性和可维护性。 ### 回答3: 在面向切面编程中,通知是一种可以插入到方法执行流程里的代码片段。前置通知在方法执行执行,后置通知在方法执行执行。在实际应用中,我们可以使用前后置通知来统计方法执行时间。 要在Spring框架中实现此功能,我们可以使用AspectJ注解或XML配置。以下是使用注解方式实现的示例代码: ```java @Aspect @Component public class MethodExecutionTimeAspect { @Around("execution(* com.example.service.*.*(..))") public Object profileTime(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = joinPoint.proceed(); long elapsedTime = System.currentTimeMillis() - startTime; System.out.println(joinPoint.getSignature() + " executed in " + elapsedTime + "ms"); return result; } } ``` 上述代码中,@Aspect注解表示这是一个切面,@Around注解表示这是一个环绕通知。execution(* com.example.service.*.*(..))表示匹配所有com.example.service包下的方法。 在方法体内,我们首先获取当前时间戳作为方法执行开始时间,然后调用joinPoint.proceed()方法执行被通知的方法,并计算方法执行时间。最后,我们输出方法签名和执行时间到控制台。 使用此切面后,我们就可以在控制台看到所有匹配的方法执行时间了。 当然,以上只是一个简单的示例代码,实际应用中还需要根据具体的业务场景进行优化。比如可以将数据存储到数据库中,可以添加异常处理功能等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值