spring AOP的方法监控要领的执行时间
前段时间有几个同行跟我吐槽说系统响应越来越慢,优化不知道从何入手!本日写写利用spring的aop来实现要领级的执行时间的记录监控,以此来评估要领的机能以及针对性的对已存在的要领举办优化。
对付监控,我们较量存眷监控的靠得住性和机能,精确,高效,这才气在不影响整体机能的环境下对我们的系统机能有个较精确的认识。
对付spring aop这个我就不多先容了,网上一搜一大把,利用过spring的人都知道spring的ioc和aop。ioc我们常用,但在我们本身的系统中,aop的利用险些为零,除了这个监控的小成果应用到了,其他的根基上没有利用到。
我们利用BeanNameAutoProxyCreator,指定bean的名称,以及被通知bean的名称,指命名称时可以利用通配符自动署理它们,设置如下
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="proxyTargetClass"> <value>true</value> </property> <property name="interceptorNames"> <list> <idref bean="profilerInterceptor" /> </list> </property> <property name="beanNames"> <list> <value>*Service</value> <value>*ServiceImpl</value> <value>*Manager</value> <value>*ManagerImpl</value> <value>*Dao</value> </list> </property> </bean>
上面的设置文件我们设置了一个idref bean,这个就是我们需要写的监控逻辑的代码。interceptor是个拦截器,上面的这个设置的所回响出来的内容是,写本身的一个拦截器来拦截后缀为Service,ServiceImpl,Manager,ManagerImpl,Dao的类,至于是类拦截照旧要领级此外拦截,那就要看我们的拦截器的逻辑和代码了。
说说拦截器的实现。我们但愿拦截器在对要领的执行时间举办记录的同时,还要举办日志的输出,如,执行时间高出500ms的要领,我们要打印出内部执行每个要领的耗时,这样我们可以对执行的慢的要领一目了然,优化时也不需要耗许多的时间去logger到底是那边执行的慢了。所以在拦截器中,我们增加一个整形的属性,这个属性用来设置需要打印到日志中高出设置时间的执行要领的耗时环境。获得像下面一样的一个日志输出:
[4359, 2, 100%, 0]com.profile.service.impl.OrderServiceImpl.findRecentlyProfile
+—[4357, 4357, 99%, 1]com.profile.dao.GenericMybatisDao.queryPage
第一行暗示整个要领执行的总耗时,下一行暗示在这个要领中存在的其他受监控的要领耗时。这就很容易让我们知道,是执行SQL所耗的时间,需要对SQL举办优化。
那到底该怎么样去实现,展示拦截器中的部门代码。拦截器担任AbstractMonitoringInterceptor类,它是一个要领级此外拦截器,实现了 MethodInterceptor 接口。
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable { String name = createInvocationTraceName(invocation); //是否委托了注解的拦截 boolean isExistsPrintProfiler = PrintProfilerHelper.isMethodExistsPrintProfiler(invocation.getMethod()); try { if (!isExistsPrintProfiler) { Profiler.start(name, monitorTime); } return invocation.proceed(); } finally { if (!isExistsPrintProfiler) { Profiler.stop(name); } } } public int getMonitorTime() { return monitorTime; } public void setMonitorTime(int monitorTime) { this.monitorTime = monitorTime; }
拦截器中的代码很是简朴,简朴到10几行代码。这对我们来说是件功德。在Profiler这个类中,我们举办了一些监控,鉴于我们输出上面所描写的日志的tree名目标日志文件,我们在Profiler中利用了TheadLocal来对执行的要领举办打点,这样会将代码变的很是简朴。Profiler的start要领也就10行代码
private final static ThreadLocal<ExecData> dataHolder = new ThreadLocal<ExecData>(); public static void start(String logName) { start(logName, ELAPSE_TIME_MS_TO_LOG); } public static void start(String logName, int elapseTimeMsToLog) { ExecData execData = dataHolder.get(); ExecNode currentNode = new ExecNode(logName, System.currentTimeMillis(), elapseTimeMsToLog); if (execData == null) { execData = new ExecData(); execData.root = currentNode; dataHolder.set(execData); } else { ExecNode parent = execData.currentNode; currentNode.setParent(parent); parent.getChildList().add(currentNode); } execData.currentNode = currentNode; execData.level++; }
#p#分页标题#e#
这样,我们就把要领的层级干系记录下来了,在执行完被监控的要领之后,我们利用stop的要领来记录执行竣事时间,并对切合条件的要领举办日志的输出。就这么几十行代码,我们很是简朴的把这个监控写完了,陈设到我们本身的应用中来监控要领的机能,以后,我们不消再去猜到底是哪个要领执行太慢了,到底是哪一步慢了。机能,监控,尽在把握中。
From:cnblogs 周蝌蚪