基于Spring AOP实现对外接口的耗时监控
2013-08-01 23:25
288 查看
AOP是Spring的核心,Spring不但自身对多种框架的集成是基于AOP,并且以非常方便的形式暴露给普通使用者。以前用AOP不多,主要是因为它以横截面的方式插入到主流程中,担心导致主流程代码不够清晰,定位问题不够方便,而在计费二期的项目里需要一个很适合用AOP来做的功能,就是要把对外接口和所调用的外部接口的耗时时间给记录下来,这个需求主要来自于计费一期的联调,常常发生系统间交互不够顺畅的情况,这就需要看每个接口调用时间来判定是谁的问题。
计费中心是整个后台系统的中间环节,与其他系统交互很多,这样的接口也很多,如果在每个接口的调用前后加时间记录比较繁琐,也影响主流程代码的美观,因此比较优雅的方式是用AOP,在不侵入原有代码的情况下,加上对接口调用的监控,并且可以在不需要的时候很容易移除。今天尝试了一下,感觉还挺好用,下面讲述一下实施步骤:
1)引入包依赖
本项目基于maven构建,因此加上包依赖比较方便,我需要的AOP依赖库有以下三个:
[xhtml] view plaincopy
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.1</version>
</dependency>
2)加上AOP的Spring配置文件
billing-spring-aop.xml:
[xhtml] view plaincopy
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="openApiLogAspect" class="com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect">
</bean>
<aop:config>
<!-- 配置aspect切面类 -->
<aop:aspect ref="openApiLogAspect">
<!-- 配置pointcut,即切入点,对哪些类的哪些方法起到AOP的作用 -->
<aop:pointcut id="EsbPriceService"
expression="execution(* org.esb.biz.product.EsbPriceService.*(..))" />
<aop:pointcut id="EsbProductService"
expression="execution(* org.esb.biz.product.EsbProductService.*(..))" />
<aop:pointcut id="IAuthorizeControllerService"
expression="execution(* com.alibaba.bss.pc2.server.remoting.IAuthorizeControllerService.*(..))" />
<aop:pointcut id="IOpenApiOrderItemService"
expression="execution(* com.alibaba.itbu.billing.api.collect.IOpenApiOrderItemService.*(..))" />
<aop:pointcut id="IOpenApiBillingCollectService"
expression="execution(* com.alibaba.itbu.billing.api.collect.IOpenApiBillingCollectService.*(..))" />
<aop:pointcut id="IOpenApiInvoiceService"
expression="execution(* com.alibaba.itbu.billing.api.invoice.IOpenApiInvoiceService.*(..))" />
<aop:pointcut id="IOpenApiChargeProductInfoService"
expression="execution(* com.alibaba.itbu.billing.api.collect.IOpenApiChargeProductInfoService.*(..))" />
<!-- 配置advice,这里采用在业务方法执行前后进行拦截 -->
<aop:around method="logExecuteTime" pointcut-ref="EsbPriceService" />
<aop:around method="logExecuteTime" pointcut-ref="EsbProductService" />
<aop:around method="logExecuteTime" pointcut-ref="IAuthorizeControllerService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiOrderItemService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiBillingCollectService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiInvoiceService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiChargeProductInfoService" />
</aop:aspect>
</aop:config>
</beans>
我是基于配置完成AOP接入,这样做的好处是不需要对原有主流程代码有任何浸入,并且也比较容易移除本AOP的拦截,这段代码主要就是配置aspect、pointcut和advice
3)编写监控耗时的advice
OpenApiLogAspect:
[java] view plaincopy
public class OpenApiLogAspect {
private static LoggerService logger = LoggerFactory.getLogger(OpenApiLogAspect.class);
public Object logExecuteTime(ProceedingJoinPoint joinPoint) throws Throwable{
Date start = new Date();
try{
return joinPoint.proceed(joinPoint.getArgs());
}catch(Exception err){
throw err;
}finally{
Date end = new Date();
logger.info("OpenApiExecuteTime:"+joinPoint.getSignature().getName()+" takes "+(end.getTime()-start.getTime())+"ms");
}
}
}
此段代码就是基于around的方式来拦截接口调用,在实际调用的前后加上时间记录,并最后在日志里打印出时间差。其中joinPoint.proceed(joinPoint.getArgs());是对实际接口的调用。
4)使监控可以配置化
此功能只会在调试阶段使用,并不需要在生产环境中运行,因此需要可以配置是否监控接口。实施这个配置化很简单,只需要通过配置决定是否把aop spring的配置文件加入到容器里就可以了,因此在总容器applicationContext.xml.vm里加上如下代码:
#if(${monitor_openapi_showTime}=="true") <import resource="classpath*:bean/billing-spring-aop.xml" /> #end
在编译打包过程中会根据变量monitor_openapi_showTime来决定是否把billing-spring-aop.xml引入进来
5)运行效果
在监控开启的情况下,若发生接口调用,能从日志里看到如下记录:
2010-01-08 18:30:13,197 [OpenApiLogAspect.java:20] [com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect] INFO com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes 71ms 2010-01-08 18:30:27,188 [OpenApiLogAspect.java:20] [com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect] INFO com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes 0ms 2010-01-08 18:30:37,838 [OpenApiLogAspect.java:20] [com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect] INFO com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes 1ms
计费中心是整个后台系统的中间环节,与其他系统交互很多,这样的接口也很多,如果在每个接口的调用前后加时间记录比较繁琐,也影响主流程代码的美观,因此比较优雅的方式是用AOP,在不侵入原有代码的情况下,加上对接口调用的监控,并且可以在不需要的时候很容易移除。今天尝试了一下,感觉还挺好用,下面讲述一下实施步骤:
1)引入包依赖
本项目基于maven构建,因此加上包依赖比较方便,我需要的AOP依赖库有以下三个:
[xhtml] view plaincopy
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.1</version>
</dependency>
2)加上AOP的Spring配置文件
billing-spring-aop.xml:
[xhtml] view plaincopy
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="openApiLogAspect" class="com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect">
</bean>
<aop:config>
<!-- 配置aspect切面类 -->
<aop:aspect ref="openApiLogAspect">
<!-- 配置pointcut,即切入点,对哪些类的哪些方法起到AOP的作用 -->
<aop:pointcut id="EsbPriceService"
expression="execution(* org.esb.biz.product.EsbPriceService.*(..))" />
<aop:pointcut id="EsbProductService"
expression="execution(* org.esb.biz.product.EsbProductService.*(..))" />
<aop:pointcut id="IAuthorizeControllerService"
expression="execution(* com.alibaba.bss.pc2.server.remoting.IAuthorizeControllerService.*(..))" />
<aop:pointcut id="IOpenApiOrderItemService"
expression="execution(* com.alibaba.itbu.billing.api.collect.IOpenApiOrderItemService.*(..))" />
<aop:pointcut id="IOpenApiBillingCollectService"
expression="execution(* com.alibaba.itbu.billing.api.collect.IOpenApiBillingCollectService.*(..))" />
<aop:pointcut id="IOpenApiInvoiceService"
expression="execution(* com.alibaba.itbu.billing.api.invoice.IOpenApiInvoiceService.*(..))" />
<aop:pointcut id="IOpenApiChargeProductInfoService"
expression="execution(* com.alibaba.itbu.billing.api.collect.IOpenApiChargeProductInfoService.*(..))" />
<!-- 配置advice,这里采用在业务方法执行前后进行拦截 -->
<aop:around method="logExecuteTime" pointcut-ref="EsbPriceService" />
<aop:around method="logExecuteTime" pointcut-ref="EsbProductService" />
<aop:around method="logExecuteTime" pointcut-ref="IAuthorizeControllerService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiOrderItemService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiBillingCollectService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiInvoiceService" />
<aop:around method="logExecuteTime" pointcut-ref="IOpenApiChargeProductInfoService" />
</aop:aspect>
</aop:config>
</beans>
我是基于配置完成AOP接入,这样做的好处是不需要对原有主流程代码有任何浸入,并且也比较容易移除本AOP的拦截,这段代码主要就是配置aspect、pointcut和advice
3)编写监控耗时的advice
OpenApiLogAspect:
[java] view plaincopy
public class OpenApiLogAspect {
private static LoggerService logger = LoggerFactory.getLogger(OpenApiLogAspect.class);
public Object logExecuteTime(ProceedingJoinPoint joinPoint) throws Throwable{
Date start = new Date();
try{
return joinPoint.proceed(joinPoint.getArgs());
}catch(Exception err){
throw err;
}finally{
Date end = new Date();
logger.info("OpenApiExecuteTime:"+joinPoint.getSignature().getName()+" takes "+(end.getTime()-start.getTime())+"ms");
}
}
}
此段代码就是基于around的方式来拦截接口调用,在实际调用的前后加上时间记录,并最后在日志里打印出时间差。其中joinPoint.proceed(joinPoint.getArgs());是对实际接口的调用。
4)使监控可以配置化
此功能只会在调试阶段使用,并不需要在生产环境中运行,因此需要可以配置是否监控接口。实施这个配置化很简单,只需要通过配置决定是否把aop spring的配置文件加入到容器里就可以了,因此在总容器applicationContext.xml.vm里加上如下代码:
#if(${monitor_openapi_showTime}=="true") <import resource="classpath*:bean/billing-spring-aop.xml" /> #end
在编译打包过程中会根据变量monitor_openapi_showTime来决定是否把billing-spring-aop.xml引入进来
5)运行效果
在监控开启的情况下,若发生接口调用,能从日志里看到如下记录:
2010-01-08 18:30:13,197 [OpenApiLogAspect.java:20] [com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect] INFO com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes 71ms 2010-01-08 18:30:27,188 [OpenApiLogAspect.java:20] [com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect] INFO com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes 0ms 2010-01-08 18:30:37,838 [OpenApiLogAspect.java:20] [com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect] INFO com.alibaba.itbu.billing.framework.aop.OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes 1ms
相关文章推荐
- 基于Spring AOP实现对外接口的耗时监控
- 【基于Spring AOP实现对外接口的耗时监控】
- 基于Spring AOP实现对外接口的耗时监控
- 基于Spring AOP实现对外接口的耗时监控
- 基于postman/newman实现的HTTP接口监控
- Hadoop Yarn内存资源隔离实现原理——基于线程监控的内存隔离方案
- 基于泛型的通用Dao接口hibernate实现
- 优雅设计封装基于Okhttp3的网络框架(六):HttpHeader接口设计实现 及 Response、Request封装实现
- OpenJWeb快速开发平台自动创建基于事务的业务逻辑接口和实现类
- 基于IP网络的数字音视频监控系统设计与实现
- 基于PHP实现微信公众平台消息接口应用开发(文本应用、地理位置、订餐系统)
- 基于Quick-cocos2dx 2.2.3 的动态更新实现完整篇。(打包,服务器接口,模块自更新)
- 基于FPGA的以太网MII接口扩展设计与实现
- 巧用插件及代码实现VIP视频源码分析观看(基于油猴插件及各大接口网站)【PC以及安卓】
- Spring Httpinvoke实现对外接口及效率提升
- 基于weibopy sina接口数据的设想与实现
- Android基于hover组件实现监控鼠标移动事件的方法
- 基于HTML5 Canvas 实现地铁站监控
- 程序设计二:基于接口程序设计思想的模板实现、面向方面的程序设计
- 基于XML的配置文件访问接口设计和实现