掌柜大作战(5):使用AOP,统一记录方法执行所花的时间

版权声明:襄阳雷哥的版权声明 https://blog.csdn.net/FansUnion/article/details/83654205

技术比较水,还是多多总结更踏实,把项目中有一定难度和一定价值的技术点,整理下思路,保存起来。
Spring中的AOP,最常用是写各种拦截器,登录拦截、权限拦截、通用参数处理。
自己的代码中,很少手动写符合AOP思想的自定义代码。

京东有UMP(统一监控平台)就是用AOP实现的,拦截目标方法,把方法执行情况和时间等,记录到本地log文件中,服务端再定时把log搬运到远程服务器,就可以实现“报警”等功能。

自己参与的一个项目,有个同事写了一个计算方法执行时间的AOP。
很久没有手写了,于是在另外一个项目,借鉴了下,最终run起来了,过程中还是遇到1个难点。

1、项目使用的4.2.5.RELEASE版本的Spring
Spring版本会影响AOP和CGLIB的一些功能效果。
比如,有网友总结如下:
spring使用动态代理或是CGLIB生成代理是有规则的,高版本的Spring会自动选择是使用动态代理还是CGLIB生成代理内容,当然我们也可以强制使用CGLIB生成代理,那就是<aop:config>里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false或者这个属性被省略,那么基于接口的代理将起作用。

2、引入AOP相关jar包
<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

3、Spring相关配置
<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>
<context:annotation-config />
4、具体例子
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
 
@Aspect
public class CostTimeMonitor extends Monitor {
    @Override
    @Pointcut("execution(* com.jd.web.controller.*.*(..))")
    protected void pointcut() {
    }
    @Override
    @Around(value = "pointcut()")
    protected Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
       Object result =  super.around(proceedingJoinPoint);
       return result;
    }
}

在spring中配置bean之后,相关代码就会被拦截。
<bean class="com.jd.CavMonitor"/>
特别需要提示的是,execution(* com.jd.web.controller.*.*(..)) 这个语法有点复杂,直接复制粘贴过来可能不起作用,因为包结构不同。

同事还是比较细心的,专门整理了一个抽象类Monitor。
public abstract class Monitor {
private static final Logger logger = LoggerFactory.getLogger(Monitor.class);

protected abstract void pointcut();

protected void beforeAdvice(JoinPoint joinPoint) {
String signature = joinPoint.getSignature().toString();
Object[] args = joinPoint.getArgs();
logger.info("执行方法:{}开始,参数:{}", signature, formatArgs(args));
}

protected void afterAdvice(JoinPoint joinPoint) {
String signature = joinPoint.getSignature().toString();
Object[] args = joinPoint.getArgs();
logger.info("执行方法:{}结束,参数:{}", signature, formatArgs(args));
}

protected Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
String signature = proceedingJoinPoint.getSignature().toString();
DateTime before = DateTime.now();
Object[] args = proceedingJoinPoint.getArgs();
Object result = proceedingJoinPoint.proceed();
DateTime after = DateTime.now();
logger.info(String.format("执行方法:%s,参数:%s,开始时间:%s,结束时间:%s,耗时:%dms", signature, formatArgs(args),
before.toString("yyyy-MM-dd HH:mm:ss.sss"), after.toString("yyyy-MM-dd HH:mm:ss.sss"),
after.getMillis() - before.getMillis()));

return result;
}

protected void afterThrowing(JoinPoint joinPoint, Throwable ex) throws Throwable {
String signature = joinPoint.getSignature().toString();
Object[] args = joinPoint.getArgs();
logger.error("执行方法:{" + signature + "}异常,参数:{" + args + "}", ex);
throw ex;
}

private String formatArgs(Object[] args) {
return String.valueOf(Arrays.asList(args));
}
}

实际效果
monitor.log.2017-09-22
[INFO][2017-09-22 16:03:19.299]执行方法:String com.jd.zc.lifecycle.web.controller.IndexController.index(Model),参数:[{countRegister=10, countBlack=0, countCertfication=24, countFreeze=1, countCooperation=3}],开始时间:2017-09-22 16:03:19.019,结束时间:2017-09-22 16:03:19.019,耗时:9ms[com.jd.zc.lifecycle.web.aop.Monitor:around]
[INFO][2017-09-22 16:03:19.522]执行方法:Result com.jd.zc.lifecycle.web.controller.SupplierTypeController.listAllSupplierOneType(),参数:[],开始时间:2017-09-22 16:03:19.019,结束时间:2017-09-22 16:03:19.019,耗时:13ms[com.jd.zc.lifecycle.web.aop.Monitor:around]
[INFO][2017-09-22 16:03:19.653]执行方法:Result com.jd.zc.lifecycle.web.controller.IndexController.listData(SupplierSummaryBean,Integer,Integer),参数:[com.jd.zc.lifecycle.bean.lifecycle.SupplierSummaryBean@284d3c86, 1, 10],开始时间:2017-09-22 16:03:19.019,结束时间:2017-09-22 16:03:19.019,耗时:141ms[com.jd.zc.lifecycle.web.aop.Monitor:around]

如果咱们再进一步把日志log格式定义精确一些,就可以再写个程序,统计方法执行时间,出报表。
也可以把日志归档起来,做个简单的文本索引和搜索功能,方便查找,定位问题。

参考资料:http://www.cnblogs.com/hongwz/p/5764917.html
--------------------- 
作者:小雷FansUnion 
来源:CSDN 
原文:https://blog.csdn.net/FansUnion/article/details/78333660 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/FansUnion/article/details/83654205