利用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日

相关文章

  • Mybatis表的关联查询详情

    您想了解“Mybatis表的关联查询详情”的完整攻略,以下是详细介绍。 Mybatis表的关联查询详情 在实际开发中,一个业务往往需要从多张表中查询数据并进行关联,这时候就需要使用表的关联查询。在 Mybatis 中,我们通常使用 XML 映射文件来实现表的关联查询。 一对一关联查询 一对一关联查询就是在两张表中建立一个一对一的关系,并且查询的两张表有主从关…

    Java 2023年5月20日
    00
  • 浅谈一下Java中集合的迭代方式

    那我开始讲解“浅谈一下Java中集合的迭代方式”。首先介绍下迭代方式的概念,简单来说,迭代方式就是对集合进行重复操作的方式,它代表了一种遍历集合元素的能力。在Java中,主要有以下三种迭代方式: 1. foreach循环迭代 使用foreach循环迭代时,需要在循环头部声明一个与集合对象所存储元素类型相匹配的变量,然后在循环体中使用该变量进行操作: List…

    Java 2023年5月26日
    00
  • java中out.print和out.write的方法

    让我来为您详细讲解Java中out.print和out.write的方法。 out.print和out.write的方法 在Java中,System.out是一个静态成员变量,它是Java标准输出流的一个对象。通过System.out,我们可以向控制台输出信息。 System.out对象有两个常用的方法:print()和write()。两者的用途相似,但细节…

    Java 2023年5月26日
    00
  • Java实现的文本字符串操作工具类实例【数据替换,加密解密操作】

    下面是Java实现的文本字符串操作工具类实例攻略,包括数据替换和加密解密操作。 一、数据替换 1.1 简介 数据替换是指将一种数据类型的值替换为另一种数据类型的值。在字符串操作中,数据替换通常是指将字符串中的特定字符或者字符串替换为其他字符或者字符串,比如将”hello world”中的”world”替换为”java”。在Java中,可以使用正则表达式或者字…

    Java 2023年5月27日
    00
  • Spring Boot配置接口WebMvcConfigurer的实现

    下面是关于“Spring Boot配置接口WebMvcConfigurer的实现”的完整攻略,包含两个示例说明。 Spring Boot配置接口WebMvcConfigurer的实现 Spring Boot提供了许多配置选项来自定义应用程序的行为。其中,WebMvcConfigurer接口提供了许多配置选项来自定义Spring MVC的行为。本文将介绍如何实…

    Java 2023年5月17日
    00
  • 我掏空了各大搜索引擎,给你整理了154道Java面试题

    我掏空了各大搜索引擎,给你整理了154道Java面试题攻略 背景 在准备Java岗位面试时,我们都会遇到这样一个问题:面试官会问哪些问题?不知道答案会不会出糗? 面对这种情况,我们不妨多花时间学习和整理Java面试题,加强自己的面试准备。 收集与整理 为了找到优质的Java面试题,我们可以从各大搜索引擎如Google、Bing、百度等中搜索相关内容。一些技术…

    Java 2023年5月20日
    00
  • Java反射,泛型在Json中的运用

    【Java反射,泛型在Json中的运用】 1. Java反射在Json中的运用 1.1 什么是Java反射 Java反射是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取对象信息以及动态调用对象方法的功能称为Java反射。 1.2 在Json中使用Java反射 在Java开发中,J…

    Java 2023年5月26日
    00
  • Hibernate框架中的缓存技术详解

    Hibernate框架中的缓存技术详解 什么是缓存? 缓存是一种提高数据库读写效率的技术。在Hibernate中,会将经常访问的数据缓存到内存中,可在内存中对该数据进行读写操作,从而提高查询效率,减少I/O操作的次数,保证了数据查询的高效性。 Hibernate中的缓存分类 Hibernate的缓存主要分为二级缓存和查询缓存: 二级缓存 二级缓存是在Sess…

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