使用Spring AOP来统计方法的执行时间

本文介绍了一种利用Spring AOP思想实现的方法执行耗时统计方案,通过面向切面编程避免了在业务代码中直接添加时间戳,提高了代码的可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、解决方案

1、传统方法

最简单、粗暴的方法是给各个需要统计的方法开始和结尾处加的时间戳,然后差值计算结果即可,代码如下:


long startTime = System.currentTimeMillis();

// 业务代码

long endTime = System.currentTimeMillis();  
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间  

这样的方式需要给很多统计方法都加上耗时时间的代码,这些代码与核心业务无关却大量重复、分散在各处,维护起来也困难。

2、面向切面编程的方法

所以,不推荐使用上面的代码。利用 Spring AOP的思想来完成这个功能,代码和相关的解释如下:

import org.apache.commons.logging.Log;  
import org.apache.commons.logging.LogFactory;  
import org.aspectj.lang.ProceedingJoinPoint;  
import org.aspectj.lang.annotation.Around;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.reflect.MethodSignature;  
import org.springframework.stereotype.Component;

/**
 * 检测方法执行耗时的spring切面类
 * 使用@Aspect注解的类,Spring将会把它当作一个特殊的Bean(一个切面),也就是不对这个类本身进行动态代理
 * @author blinkfox
 * @date 2016-07-04
 */
@Aspect
@Component
public class TimeInterceptor {

    private static Log logger = LogFactory.getLog(TimeInterceptor.class);

    // 一分钟,即60000ms
    private static final long ONE_MINUTE = 60000;

    // service层的统计耗时切面,类型必须为final String类型的,注解里要使用的变量只能是静态常量类型的
    public static final String POINT = "execution (* com.blinkfox.test.service.impl.*.*(..))";

    /**
     * 统计方法执行耗时Around环绕通知
     * @param joinPoint
     * @return
     */
    @Around(POINT)
    public Object timeAround(ProceedingJoinPoint joinPoint) {
        // 定义返回对象、得到方法需要的参数
        Object obj = null;
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();

        try {
            obj = joinPoint.proceed(args);
        } catch (Throwable e) {
            logger.error("统计某方法执行耗时环绕通知出错", e);
        }

        // 获取执行的方法名
        long endTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getDeclaringTypeName() + "." + signature.getName();

        // 打印耗时的信息
        this.printExecTime(methodName, startTime, endTime);

        return obj;
    }

    /**
     * 打印方法执行耗时的信息,如果超过了一定的时间,才打印
     * @param methodName
     * @param startTime
     * @param endTime
     */
    private void printExecTime(String methodName, long startTime, long endTime) {
        long diffTime = endTime - startTime;
        if (diffTime > ONE_MINUTE) {
            logger.warn("-----" + methodName + " 方法执行耗时:" + diffTime + " ms");
        }
    }

}

注意:最后还需要在 applicationContext.xml文件中加上AOP需要的配置 <aop:aspectj-autoproxy/>,这样Spring才能识别到它。
### 使用 Spring AOP 实现接口调用链路中每个方法执行时间的统计 要实现对接口调用链路中每个方法执行时间的统计,可以通过 SpringAOP 功能来完成。以下是具体的实现方式: #### 1. 创建自定义注解 首先,可以创建一个自定义注解用于标记需要统计执行时间方法。 ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface TrackExecutionTime { String value() default ""; } ``` 此注解 `TrackExecutionTime` 可以附加到任何需要监控其执行时间方法上[^4]。 --- #### 2. 编写切面类 接着,编写一个切面类(Aspect),利用 Spring AOP 对带有 `@TrackExecutionTime` 注解的方法进行拦截,并记录它们的执行时间。 ```java import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class ExecutionTimeTracker { @Around("@annotation(TrackExecutionTime)") public Object trackExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.nanoTime(); // 开始时间 try { return joinPoint.proceed(); } finally { long endTime = System.nanoTime(); // 结束时间 long duration = (endTime - startTime) / 1_000_000; // 转换为毫秒 String methodName = joinPoint.getSignature().toShortString(); System.out.println(methodName + " 执行时间为:" + duration + " ms"); } } } ``` 在这个切面类中,使用了 `@Around` 切点表达式来捕获所有被 `@TrackExecutionTime` 注解标注的方法。通过计算 `System.nanoTime()` 差值获取方法的实际运行时间,并打印出来[^5]。 --- #### 3. 配置 Spring AOP 支持 确保项目中的 Spring 配置文件启用了 AOP 支持。如果是基于 Java Config,则可以在配置类中标记 `@EnableAspectJAutoProxy`。 ```java import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy public class AppConfig { // 其他 bean 配置... } ``` 启用自动代理功能后,Spring 将负责为目标对象生成代理实例并应用切面逻辑[^6]。 --- #### 4. 测试代码 最后,在业务层的一个服务类中添加测试方法,并为其加上 `@TrackExecutionTime` 注解。 ```java import org.springframework.stereotype.Service; @Service public class MyService { @TrackExecutionTime(value = "testMethod") public void performTask() { try { Thread.sleep(200); // 模拟耗时操作 } catch (InterruptedException e) { throw new RuntimeException(e); } } } ``` 当调用 `performTask()` 方法时,控制台将会输出类似如下日志: ``` MyService.performTask() 执行时间为:208 ms ``` --- ### 总结 以上方案展示了如何借助 Spring AOP 和自定义注解轻松实现对特定方法执行时间的跟踪和统计。这种方法不仅简单易懂,还具有高度可扩展性和灵活性,能够满足大多数实际开发需求[^7]。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值