您的位置:首页 > 编程语言 > Java开发

使用Spring AOP添加统计时间的功能

2016-09-30 09:43 351 查看
最近有个需求,需要统计各个接口、类的方法的执行时间,但是要尽量不影响原来业务,不改变原有代码。

第一想到的就是使用AOP的方式来做,翻了一些资料,终于把问题解决了。这里整理一下:

Spring提供了4种实现AOP的方式:

1.经典的基于代理的AOP

2.@AspectJ注解驱动的切面

3.纯POJO切面

4.注入式AspectJ切面

我这里讲到的是使用@AspectJ注解驱动的方式,其他的可以自行研究一下。

首先我的项目是使用SpringMVC+Spring+Mybatis的结构,使用aop的方式,需要修改一下SpringMVC.xml配置。

1、增加AOP的XML命名空间和声明相关schema

命名空间:

xmlns:aop="http://www.springframework.org/schema/aop"


schema声明:

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd[/code] 
2、然后添加如下配置:

<!-- 开启切面编程功能 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>


之后是编写我们的切面类:

package com.mysite.common.system;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspect
4000
j.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.mysite.common.entity.TimeEntity;
import com.mysite.common.util.SendHearbeatUtil;

@Component
@Aspect
public class StatisticHelper {
private long startTime = 0;

//对com.mysite.test包下面所有子包所有public方法有效,此方法不能有返回值
@Pointcut("execution(public * com.mysite.test..*.*(..))")
public void recordTime() {
}

@Before("recordTime()")
public void before(JoinPoint jp) {
startTime = System.currentTimeMillis();//获取访问时的当前时间
}

@AfterReturning("recordTime()")
public void afterReturning(JoinPoint jp) {
long process = System.currentTimeMillis() - startTime;//计算出调用方法返回的用时
String className = jp.getThis().toString();//获取类名
String methodName = jp.getSignature().getName(); // 获得方法名
TimeEntity e = new TimeEntity();
e.setClazz(className);
e.setMethod(methodName);
e.setTime(process);
SendHearbeatUtil.pq.add(e);//把timeEntity放入SendHearbeatUtil中的队列中待处理
}
}


这样我们的切面程序就已经完成。

在我们访问com.mysite.test包下面类的方法时,会启用切面统计。

Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合.

args()
@args()
execution()
this()
target()
@target()
within()
@within()
@annotation
比如 @Pointcut("execution(public * com.mysite.test..*.*(..))") 可以写成:

@Pointcut("within(com.mysite.test..*)")

如果需要对多个包进行AOP,可以写成

@Pointcut("execution(public * com.mysite.test1..*.*(..)) or execution(public * com.mysite.test2..*.*(..))")

或者

@Pointcut("execution(public * com.mysite.test1..*.*(..)) || execution(public * com.mysite.test2..*.*(..))")

编写切面类的要点

@Aspect放在类头上,把这个类作为一个切面。

@Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。

5种通知:

1、@Before,前置通知,放在方法头上。

2、@After,后置【finally】通知,放在方法头上。

3、@AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。

4、@AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。

5、@Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: