利用Spring AOP记录方法的执行时间

利用Spring AOP记录方法的执行时间可以通过以下步骤实现:

1. 添加依赖

pom.xml文件中添加Spring AOP的依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
</dependency>

2. 定义切面类

切面类必须实现org.aspectj.lang.annotation.Aspect接口,并使用@Aspect注解标记:

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class PerformanceAspect {
    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);

    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    public void controllerExecution() {}

    @Before("controllerExecution()")
    public void beforeControllerExecution() {
        logger.info("Start executing controller");
    }

    @After("controllerExecution()")
    public void afterControllerExecution() {
        logger.info("Finish executing controller");
    }
}

上述代码定义了一个切面类PerformanceAspect,用来记录所有Controller中方法的执行时间。其中,@Pointcut注解用于定义切入点,该切入点匹配所有Controller中的方法;@Before@After注解用于在目标方法执行之前和执行之后分别执行自定义的逻辑。

3. 配置AOP

在Spring配置文件中添加如下配置:

<aop:aspectj-autoproxy />
<bean id="performanceAspect" class="com.example.demo.aop.PerformanceAspect" />

上述配置会自动扫描并代理Spring容器中的所有@Aspect注解标记的切面类。

4. 测试

定义一个简单的Controller:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @GetMapping("/hello")
    public String hello() throws InterruptedException {
        Thread.sleep(1000);
        return "Hello, World!";
    }
}

启动应用程序并访问http://localhost:8080/hello,控制台将输出如下日志:

Start executing controller
Finish executing controller

日志表明,PerformanceAspect切面类成功地拦截了DemoController中的方法,并记录了方法的执行时间。下面再提供一条完整的代码示例:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SystemLogAspect {

    private static final Logger log = LoggerFactory.getLogger(SystemLogAspect.class);

    /**
     * 定义切入点,拦截所有带有RequestMapping注解的方法
     */
    @Pointcut("execution(public * com.scienjoy.app.web..*Controller.*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void controllerMethod() {
    }

    /**
     * 前置通知,方法调用前被调用
     * @param joinPoint 连接点对象,封装了被拦截方法的信息
     */
    @Before("controllerMethod()")
    public void beforeMethod(JoinPoint joinPoint) {
        log.info("调用了 " + joinPoint.getTarget().getClass().getName() + " 的 " + joinPoint.getSignature().getName() + " 方法,参数: " + joinPoint.getArgs());
    }

    /**
     * 后置通知,在方法执行完毕后执行,无论方法成功执行还是出现异常都会执行
     * @param joinPoint 连接点对象
     * @param result 方法返回值
     */
    @AfterReturning(pointcut = "controllerMethod()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        //把返回值转化为String类型,防止调用toString()方法时出现空指针异常
        String ret = result != null ? result.toString() :"null";
        log.info("调用 " + joinPoint.getTarget().getClass().getName() + " 的 " + joinPoint.getSignature().getName() + " 方法成功结束,返回值: " + ret);
    }

    /**
     * 异常通知,在拦截的方法出现异常时被调用
     * @param joinPoint 连接点对象
     * @param throwable 异常对象
     */
    @AfterThrowing(pointcut = "controllerMethod()", throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
        log.error("调用 " + joinPoint.getTarget().getClass().getName() + " 的 " + joinPoint.getSignature().getName() + " 方法时出现异常: " + throwable.getMessage());
    }

    /**
     * 环绕通知,可以控制拦截方法的执行过程
     * @param proceedingJoinPoint 连接点
     * @return 拦截方法执行结果
     * @throws Throwable 异常
     */
    @Around("controllerMethod()")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("开始调用 " + proceedingJoinPoint.getTarget().getClass().getName() + " 的 " + proceedingJoinPoint.getSignature().getName() + " 方法");
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throw throwable;
        } finally {
            long endTime = System.currentTimeMillis();
            log.info("调用 " + proceedingJoinPoint.getTarget().getClass().getName() + " 的 " + proceedingJoinPoint.getSignature().getName() + " 方法结束,耗时: " + (endTime - startTime) + "ms");
        }
        return result;
    }
}

该切面类实现了前置通知、后置通知、异常通知以及环绕通知功能,能够较全面地记录方法执行时间和出现的异常情况。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:利用Spring AOP记录方法的执行时间 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java SPI机制原理及代码实例

    Java SPI机制原理及代码实例 SPI全称Service Provider Interface。在Java中,SPI是一种以插件化的方式来实现程序的可扩展性的机制,它允许第三方程序向已有的程序添加功能或者替换原有的功能。 SPI的机制原理 SPI机制的基本原理是,一些具有相同接口的服务类,定义了一组标准与规范,由服务提供者实现,以供调用方调用。调用者通过…

    Java 2023年5月19日
    00
  • 深入理解PHP之OpCode原理详解

    深入理解PHP之OpCode原理详解 背景 在PHP编程中,我们通常编写的PHP代码都需要通过解释器来完成解释运行。PHP解释器在执行解释过程中,需要将PHP代码转换为计算机所能理解的二进制指令。这些二进制指令被称为OpCode,也就是操作码。本文将主要介绍OpCode在PHP解释器中的作用以及原理。 OpCode的作用 在PHP解释器解析PHP代码时,每行…

    Java 2023年5月26日
    00
  • 使用jackson实现对象json之间的相互转换(spring boot)

    下面是使用Jackson库实现对象和JSON格式的相互转换的完整攻略。 前置条件 本文需要你已经掌握Spring Boot框架的基础知识,并且对于Java对象与JSON的基础知识有所了解。 介绍 Jackson是一个Java库,用于将Java对象序列化为JSON格式的字符串,并将JSON格式的字符串反序列化为Java对象。Jackson支持在Java对象和J…

    Java 2023年5月26日
    00
  • Java基础异常处理代码及原理解析

    Java基础异常处理代码及原理解析 什么是异常处理? Java中的异常指的是程序在运行过程中遇到的错误或异常情况,比如说除数为零、数组下标越界、空指针等。为了保证程序的正常运行,我们需要对这些异常情况进行处理,避免程序崩溃或者出现无法预料的结果。 在Java中,异常处理机制分为两种:检查性异常和非检查性异常。检查性异常需要在代码中进行处理,如IOExcept…

    Java 2023年5月30日
    00
  • Spring Boot如何优化内嵌的Tomcat示例详解

    针对这个问题,我来详细讲解一下Spring Boot如何优化内嵌的Tomcat,包含以下内容: 1. 优化内嵌Tomcat的原因 Spring Boot在内嵌Tomcat作为HTTP服务器的情况下,处理请求效率较低,主要原因是默认的Tomcat设置了大量的属性,例如发送缓存和接收缓存大小、最大线程数等,这些设置并不一定适用于所有应用程序。因此,我们需要对内嵌…

    Java 2023年5月19日
    00
  • 高命中率的varnish缓存配置分享

    下面我来为你详细讲解“高命中率的varnish缓存配置分享”的完整攻略。 一、背景介绍 Varnish是一款高性能的HTTP反向代理服务器,它可以加速站点的访问速度,并为站点提供缓存服务。在使用Varnish时,我们需要合理配置缓存策略来提高缓存命中率和性能。 二、缓存策略配置 1. 确定缓存内容 首先,我们需要确定哪些内容需要缓存。可以根据站点的特点和访问…

    Java 2023年6月16日
    00
  • Spring注解驱动之BeanFactoryPostProcessor原理解析

    Spring注解驱动之BeanFactoryPostProcessor原理解析 在Spring中,BeanFactoryPostProcessor是Spring IoC容器提供的一个扩展点,它可以在Bean被实例化之前,对Bean进行改变或者增强。本文就详细介绍一下BeanFactoryPostProcessor的原理以及示例说明。 BeanFactoryP…

    Java 2023年5月31日
    00
  • java实现的RC4加密解密算法示例

    Java实现的RC4加密解密算法示例 什么是RC4加密算法 RC4(Rivest Cipher 4)是一种流加密算法,又称ARC4(Alleged RC4),由Ronald Rivest在1987年设计。RC4是一种常用的对称密钥加密算法,它可以用于加密/解密数据。RC4的优点是算法简单、高效,并且可以根据加密数据动态地生成密钥流,从而保障加密数据的安全性。…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部