基于Spring AOP实现对外接口的耗时监控

 AOP是Spring的核心 Spring不但自身对多种框架的集成是基于AOP 并且以非常方便的形式暴露给普通使用者 以前用AOP不多 主要是因为它以横截面的方式插入到主流程中 担心导致主流程代码不够清晰 定位问题不够方便 而在计费二期的项目里需要一个很适合用AOP来做的功能 就是要把对外接口和所调用的外部接口的耗时时间给记录下来 这个需求主要来自于计费一期的联调 常常发生系统间交互不够顺畅的情况 这就需要看每个接口调用时间来判定是谁的问题

 计费中心是整个后台系统的中间环节 与其他系统交互很多 这样的接口也很多 如果在每个接口的调用前后加时间记录比较繁琐 也影响主流程代码的美观 因此比较优雅的方式是用AOP 在不侵入原有代码的情况下 加上对接口调用的监控 并且可以在不需要的时候很容易移除 今天尝试了一下 感觉还挺好用 下面讲述一下实施步骤

  )引入包依赖

 本项目基于maven构建 因此加上包依赖比较方便 我需要的AOP依赖库有以下三个

 [x]

 <dependency>

 <groupId> springframework</groupId>

 <artifactId>spring aop</artifactId>

 <version> </version>

 </dependency>

 <dependency>

 <groupId> aspectj</groupId>

 <artifactId>aspectjweaver</artifactId>

 <version> </version>

 </dependency>

 <dependency>

 <groupId> aspectj</groupId>

 <artifactId>aspectjrt</artifactId>

 <version> </version>

 </dependency>

 <dependency>

 <groupId> springframework</groupId>

 <artifactId>spring aop</artifactId>

 <version> </version>

 </dependency>

 <dependency>

 <groupId> aspectj</groupId>

 <artifactId>aspectjweaver</artifactId>

 <version> </version>

 </dependency>

 <dependency>

 <groupId> aspectj</groupId>

 <artifactId>aspectjrt</artifactId>

 <version> </version>

 </dependency>

  )加上AOP的Spring配置文件

 billing spring aop xml:

 [x]

 <?xml version= encoding= UTF ?>

 <beans xmlns=

 xmlns:xsi= instance

 xmlns:aop=

 xmlns:tx=

 xsi:schemaLocation= beans xsd

  aop xsd

  tx xsd >

 <bean id= openApiLogAspect class= bu billing framework aop OpenApiLogAspect >

 </bean>

 <aop:config>

 <! 配置aspect切面类 >

 <aop:aspect ref= openApiLogAspect >

 <! 配置pointcut 即切入点 对哪些类的哪些方法起到AOP的作用 >

 <aop:pointcut id= E *** PriceService

 expression= execution(* product E *** PriceService *()) />

 <aop:pointcut id= E *** ProductService

 expression= execution(* product E *** ProductService *()) />

 <aop:pointcut id= IAuthorizeControllerService

 expression= execution(* alibaba bss pc server remoting IAuthorizeControllerService *()) />

 <aop:pointcut id= IOpenApiOrderItemService

 expression= execution(* llect IOpenApiOrderItemService *()) />

 <aop:pointcut id= IOpenApiBillingCollectService

 expression= execution(* llect IOpenApiBillingCollectService *()) />

 <aop:pointcut id= IOpenApiInvoiceService

 expression= execution(* bu billing api invoice IOpenApiInvoiceService *()) />

 <aop:pointcut id= IOpenApiChargeProductInfoService

 expression= execution(* llect IOpenApiChargeProductInfoService *()) />

 <! 配置advice 这里采用在业务方法执行前后进行拦截 >

 <aop:around method= logExecuteTime pointcut ref= E *** PriceService />

 <aop:around method= logExecuteTime pointcut ref= E *** ProductService />

 <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>

 <?xml version= encoding= UTF ?>

 <beans xmlns=

 xmlns:xsi= instance

 xmlns:aop=

 xmlns:tx=

 xsi:schemaLocation= beans xsd

  aop xsd

  tx xsd >

 <bean id= openApiLogAspect class= bu billing framework aop OpenApiLogAspect >

 </bean>

 <aop:config>

 <! 配置aspect切面类 >

 <aop:aspect ref= openApiLogAspect >

 <! 配置pointcut 即切入点 对哪些类的哪些方法起到AOP的作用 >

 <aop:pointcut id= E *** PriceService

 expression= execution(* product E *** PriceService *()) />

 <aop:pointcut id= E *** ProductService

 expression= execution(* product E *** ProductService *()) />

 <aop:pointcut id= IAuthorizeControllerService

 expression= execution(* alibaba bss pc server remoting IAuthorizeControllerService *()) />

 <aop:pointcut id= IOpenApiOrderItemService

 expression= execution(* llect IOpenApiOrderItemService *()) />

 <aop:pointcut id= IOpenApiBillingCollectService

 expression= execution(* llect IOpenApiBillingCollectService *()) />

 <aop:pointcut id= IOpenApiInvoiceService

 expression= execution(* bu billing api invoice IOpenApiInvoiceService *()) />

 <aop:pointcut id= IOpenApiChargeProductInfoService

 expression= execution(* llect IOpenApiChargeProductInfoService *()) />

 <! 配置advice 这里采用在业务方法执行前后进行拦截 >

 <aop:around method= logExecuteTime pointcut ref= E *** PriceService />

 <aop:around method= logExecuteTime pointcut ref= E *** ProductService />

 <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

  )编写监控耗时的advice

 OpenApiLogAspect:

 [java]

 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();

 ( OpenApiExecuteTime: +joinPoint getSignature() getName()+ takes +(end getTime() start getTime())+ ms );

 }

 }

 }

 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();

 ( OpenApiExecuteTime: +joinPoint getSignature() getName()+ takes +(end getTime() start getTime())+ ms );

 }

 }

 }

 此段代码就是基于around的方式来拦截接口调用 在实际调用的前后加上时间记录 并最后在日志里打印出时间差 其中joinPoint proceed(joinPoint getArgs());是对实际接口的调用

  )使监控可以配置化

 此功能只会在调试阶段使用 并不需要在生产环境中运行 因此需要可以配置是否监控接口 实施这个配置化很简单 只需要通过配置决定是否把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引入进来

  )运行效果

 在监控开启的情况下 若发生接口调用 能从日志里看到如下记录

  : : [OpenApiLogAspect java: ] [bu billing framework aop OpenApiLogAspect] INFO bu billing framework aop OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes ms

  : : [OpenApiLogAspect java: ] [bu billing framework aop OpenApiLogAspect] INFO bu billing framework aop OpenApiLogAspect :: OpenApiExecuteTime:installOrderItem takes ms

lishixinzhi/Article/program/Java/ky/201311/28361