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

1.  需求 背景
性能调优阶段,需要找出执行时间比较长的方法,针对这些方法进行调优。
 
2.  可行方案
一种是传统的在每个方法前后获取System.currentMis(),然后得到方法的执行时间。
这种方式的缺点是方法多会写很多耦合代码,而且不可重用,测试完需要删掉。
 
另一种使用AOP监控方法的前后点,监控方法的执行时间,比较优雅且无侵入。
可行的方案之一是使用 Around Advice, 环绕通知可在方法执行前后做一些操作。
 
AOP,面向切面编程,Aspect Oriented Programming, 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
 
3. AOP
jar librarys requires:
<dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
    <version>1.5.4</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
     <artifactId>cglib-nodep</artifactId>
      <version>2.2</version>
</dependency>
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.6</version>
</dependency>
 
Spring配置:
<aop:aspectj-autoproxy proxy-target-class="true"/>
  
AOP实现类:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

/**
 * Created by jzq1999 on 2017/4/19.
 * 通过aop拦截后执行具体操作
 */
@Aspect
@Component
public class DaoTimeInterceptor {

    private final static String POINT = "execution (* com.tzx.*.po.springjdbc.dao.imp.*.*(..))";

    @Pointcut(POINT)
    public void recordLog(){}

    @Around("recordLog()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object obj = pjp.proceed(pjp.getArgs());
        stopWatch.stop();

        long cost = stopWatch.getTotalTimeMillis();
        if(cost > 10) {
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            String methodName = signature.getDeclaringTypeName() + "." + signature.getName();

            System.out.println("----------- 执行" + methodName + "方法, 用时: " + cost + "ms -----------");
        }

        return obj;
    }

}
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答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()方法执行被通知的方法,并计算方法执行时间。最后,我们输出方法签名和执行时间到控制台。 使用此切面后,我们就可以在控制台看到所有匹配的方法执行时间了。 当然,以上只是一个简单的示例代码,实际应用中还需要根据具体的业务场景进行优化。比如可以将数据存储到数据库中,可以添加异常处理功能等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值