Spring AOP 性能监控器
spring,真是一个好东西;性能,真是个让人头疼又不得不面对的问题。如何排查出项目中性能瓶颈?如何迅速定位系统的慢查询?在这我就不说spring自带的性能监控器了,实在是有些简陋。下面就说说我自己写的这个性能监控器。先看看效果:
其实,利用spring AOP,任何人都可以写一个定制的监控,但大体思路是一样的,就是在被调用方法的开始之前,记录一下开始时间,在调用方法结束之后,记录结束时间,然后,在调用栈退出前,将日志打印出来。光说不练假把式,下面一步一步构建一个性能监控器。
step1.构造拦截器。
直接上代码,拦截器核心代码:
public Object invoke(MethodInvocation invocation) throws Throwable {
try {
String name = extractLogName(invocation);
//记录开始时间
start(name);
return invocation.proceed();
} finally {
//记录方法结束时间
stop();
}
}
因为最终要打印出来,因此,打印的名称必须在记录时间时把被调用方法的名称也记录下来。方法extractLogName就是干这个的。
step2.构造数据结构
首先,我们需要一个线程变量,存储AOP拦截的每个方法的开始时间及结束时间。就用threadLocal变量了,本人还没想到更好的方法。其次,调用过程其实是在一个方法栈(Stack)中旅行了一遍,被调用的方法总是后进先出。每进一个方法,都要记录一个开始时间,每当退出一个方法,都要记录这个方法运行的结束时间。最终,我们将得到一个类似树形的结构。我们需要定义这个结构,以便我们在退出方法栈时能够将每一个方法所耗费的时间都打印出来。
StackData定义了根节点的结构,StackEntry存储每个方法的开始结束时间,另外在StackData和StackEntry加入level字段,方便后面打印日志。StackData和StackEntry都是作为一个内部类引入的,因为这两个类为了性能,都没有提供一些封装方法,不宜暴露出去(出去多丢人啊)。
好了,结构和拦截器都写好了。只需两步,大工基本就告成了,在拦截器中,在调用方法的前面及后面,记录一个StackEntry对象就可以了。start和stop的代码如下:
public static void start(String logName) {
StackData data = dataHolder.get();
StackEntry currentEntry = new StackEntry(logName, System.currentTimeMillis());
if (data == null) {
data = new StackData();
data.root = currentEntry;
data.level = 1;
dataHolder.set(data);
} else {
StackEntry parent = data.currentEntry;
currentEntry.parent=parent;
parent.child.add(currentEntry);
}
data.currentEntry = currentEntry;
currentEntry.level=data.level;
data.level++;
}
public static void stop() {
StackData data = dataHolder.get();
StackEntry self = data.currentEntry;
self.endTime = System.currentTimeMillis();
data.currentEntry = self.parent;
data.level--;
printStack(data);
}
/**
* 此处还可以进行改进,可以将超时的数据放入一个有界队列
* 里,在另一个线程进行打印。
* @param data
*/
private static void printStack(StackData data) {
if(logger.isWarnEnabled()){
StringBuilder sb = new StringBuilder("\r\n");
StackEntry root = data.root;
appendNode(root,sb);
logger.warn(sb.toString());
}
} private static void appendNode(StackEntry entry, StringBuilder sb) {
long totalTime = entry.endTime-entry.beginTime ;
if(entry.level ==1){
sb.append("|-");
}
sb.append(totalTime);
sb.append(" ms; [");
sb.append(entry.logName);
sb.append("]"); for(StackEntry cnode : entry.child){
sb.append("\r\n|");
for(int i=0,l=entry.level;i<l;i++){
sb.append("+---");
}
appendNode(cnode,sb);
} }
等等,还有需求?
1、我们只想找出慢查询,而不想把所有的方法的运行时间都打印出来
2、希望有一个开关,平常不需要监控,在出现问题的时候,才把这个监控打开。
好吧,程序员都是被这些需求给搞死的。
在拦截器中增加一个开关switchOn和一个阈值threshold,当switchOn==true的时候,才进行监控,否则不监控。在监控时,如果整个方法的运行时间小于threshold,不打印日志,因为打印日志会IO,会给方法增加额外的开销。改进后代码如下:
打印日志阈值:
到此,这个性能监控器几乎算完美了。
但这个监控器是运行在spring AOP上面的,并且,监控的方法必须都是通过interface调用的。所以,如果你要使用这个方法,还要确保你是使用的面向接口的编程。不过,如果你的项目没有使用面向接口,可以利用eclipse自带的工具,将公用方法Extract成interface。
spring怎么配置?拦截器怎么配置?你不会连这个都不会吧,那你搜索一下吧。
PS:暂时未提供spring3.0的实现。
Spring AOP 性能监控器的更多相关文章
- Spring AOP在函数接口调用性能分析及其日志处理方面的应用
面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...
- Spring AOP切点表达式用法总结
1. 简介 面向对象编程,也称为OOP(即Object Oriented Programming)最大的优点在于能够将业务模块进行封装,从而达到功能复用的目的.通过面向对象编程,不同的模 ...
- spring aop
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将 ...
- 基于Spring AOP的JDK动态代理和CGLIB代理
一.AOP的概念 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的 ...
- 从零开始学 Java - Spring AOP 实现主从读写分离
深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...
- Spring AOP /代理模式/事务管理/读写分离/多数据源管理
参考文章: http://www.cnblogs.com/MOBIN/p/5597215.html http://www.cnblogs.com/fenglie/articles/4097759.ht ...
- spring AOP应用
转自:http://wb284551926.iteye.com/blog/1887650 最近新项目要启动,在搭建项目基础架构的时候,想要加入日志功能和执行性能监控的功能,想了很多的想法,最后还是想到 ...
- 二、Spring——AoP
AOP概述 AOP是OOP的有益补充,他为程序开发提供了一个崭新的思考角度,可以将重复性的横切逻辑抽取到统一的模块中,通过OOP的纵向抽象和AOP的横向抽取,程序才能真正解决复杂性代码问题. Spri ...
- Spring AOP小结
一. AOP介绍 AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP ...
随机推荐
- Android之调试打印
- Ceph Newstore存储引擎介绍
在Ceph被越来越多地应用于各项存储业务过程中,其性能及调优策略也成为用户密切关注讨论的话题,影响性能表现关键因素之一即OSD存储引擎实现:Ceph基础组件RADOS是强一致.对象存储系统,其OSD底 ...
- 转:Unity3D的四种坐标系
World Space(世界坐标):我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的.transform.position可以获得该位置坐标. Screen Space(屏幕坐标 ...
- VS2015+AngularJS+Ionic开发
安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...
- 国外一些知名ASP.Net开源CMS系统
1.Ludico Ludico是C#编写的居于ASP.NET 2.0的Portal/CMS系统.它的模块化设计是你可以按照你希望的使用或开发网站功能.它里面有高级的用户管理,一个所见即所的(WYSIW ...
- WCF编程系列(七)信道及信道工厂
WCF编程系列(七)信道及信道工厂 信道及信道栈 前面已经提及过,WCF中客户端与服务端的交互都是通过消息来进行的.消息从客户端传送到服务端会经过多个处理动作,在WCF编程模型中,这些动作是按层 ...
- JAVA操作LDAP总结
一.LDAP概念 LDAP的全称为Lightweight Directory Access Protocol(轻量级目录访问协议), 基于X.500标准, 支持 TCP/IP. LDAP目录为数据库, ...
- C# ACM poj1008
玛雅历 public static void Acm1008(int day, string mon, int year) { ; switch (mon) { case "pop" ...
- extern int a[] VS extern int *a
array VS pointer 参考: 1.Extern using pointer instead of array array is not pointer 2.extern array que ...
- POJ 2777(线段树)
Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 42507 Accepted: 12856 Des ...