在我们的实际开发中,多多少少会遇到统计一段代码片段的耗时的情况,我们一般的写法如下
1 | 复制代码long start = System.currentTimeMillis(); |
上面的写法没有什么毛病,但是看起来就不太美观了,那么有没有什么更优雅的写法呢?
1. 代理方式
了解 Spring AOP 的同学可能立马会想到一个解决方法,如果想要统计某个方法耗时,使用切面可以无侵入的实现,如
1 | 复制代码// 定义切点,拦截所有满足条件的方法 |
Spring AOP 的底层支持原理为代理模式,为目标对象提供增强功能;在 Spring 的生态体系下,使用 aop 的方式来统计方法耗时,可以说少侵入且实现简单,但是有以下几个问题
- 统计粒度为方法级别
- 类内部方法调用无法生效(详情可以参考博文:【SpringBoot 基础系列教程】AOP 之高级使用技能)
2. AutoCloseable
在 JDK1.7 引入了一个新的接口AutoCloseable
, 通常它的实现类配合try{}
使用,可在 IO 流的使用上,经常可以看到下面这种写法
1 | 复制代码// 读取文件内容并输出 |
注意上面的写法中,最值得关注一点是,不需要再主动的写stream.close
了,主要原因就是在try(){}
执行完毕之后,会调用方法AutoCloseable#close
方法;
基于此,我们就会有一个大单的想法,下一个Cost
类实现AutoCloseable
接口,创建时记录一个时间,close 方法中记录一个时间,并输出时间差值;将需要统计耗时的逻辑放入try(){}
代码块
下面是一个具体的实现:
1 | 复制代码public static class Cost implements AutoCloseable { |
执行后输出如下:
1 | 复制代码now 0 |
如果代码块抛异常,也会正常输出耗时么?
1 | 复制代码public static void testPrint() { |
再次输出如下,并没有问题
1 | 复制代码now 0 |
3. 小结
除了上面介绍的两种方式,还有一种在业务开发中不太常见,但是在中间件、偏基础服务的功能组件中可以看到,利用 Java Agent 探针技术来实现,比如阿里的 arthas 就是在 JavaAgent 的基础上做了各种上天的功能,后续介绍 java 探针技术时会专门介绍
下面小结一下三种统计耗时的方式
基本写法
1 | 复制代码long start = System.currentTimeMillis(); |
优点是简单,适用范围广泛;缺点是侵入性强,大量的重复代码
Spring AOP
在 Spring 生态下,可以借助 AOP 来拦截目标方法,统计耗时
1 | 复制代码@Around("...") |
优点:无侵入,适合统一管理(比如测试环境输出统计耗时,生产环境不输出);缺点是适用范围小,且粒度为方法级别,并受限于 AOP 的使用范围
AutoCloseable
这种方式可以看做是第一种写法的进阶版
1 | 复制代码// 定义类 |
优点是:简单,适用范围广泛,且适合统一管理;缺点是依然有代码侵入
说明
上面第二种方法看着属于最优雅的方式,但是限制性强;如果有更灵活的需求,建议考虑第三种写法,在代码的简洁性和统一管理上都要优雅很多,相比较第一种可以减少大量冗余代码
II. 其他
1. 一灰灰 Blog: liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现 bug 或者有更好的建议,欢迎批评指正,不吝感激
- 微博地址: 小灰灰 Blog
- QQ: 一灰灰/3302797840
3. 扫描关注
一灰灰 blog
本文转载自: 掘金