AOP是Spring的核心,Spring不但自身对多种框架的集成是基于AOP,并且以非常方便的形式暴露给普通使用者。以前用AOP不多,主要是因为它以横截面的方式插入到主流程中,担心导致主流程代码不够清晰,定位问题不够方便,而在计费二期的项目里需要一个很适合用AOP来做的功能,就是要把对外接口和所调用的外部接口的耗时时间给记录下来,这个需求主要来自于计费一期的联调,常常发生系统间交互不够顺畅的情况,这就需要看每个接口调用时间来判定是谁的问题。
计费中心是整个后台系统的中间环节,与其他系统交互很多,这样的接口也很多,如果在每个接口的调用前后加时间记录比较繁琐,也影响主流程代码的美观,因此比较优雅的方式是用AOP,在不侵入原有代码的情况下,加上对接口调用的监控,并且可以在不需要的时候很容易移除。今天尝试了一下,感觉还挺好用,下面讲述一下实施步骤:
1)引入包依赖
本项目基于maven构建,因此加上包依赖比较方便,我需要的AOP依赖库有以下三个:
<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>
<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:
<?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>
<?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:
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");
}
}
}
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
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cutesource/archive/2010/01/09/5163467.aspx
分享到:
相关推荐
基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop
代码实现简单,易于维护:使用 Spring AOP 可以将耗时监测的逻辑与业务逻辑进行解耦,避免业务逻辑代码的冗余和代码维护难度的提高。 2. 安全性高:使用 Spring AOP 进行方法耗时监测,可以在不修改业务逻辑代码的...
NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927
Spring AOP的实现机制中文版,动态代理及原理,自定义类加载器
演示了spring基于AOP代理TransactionProxyFactoryBean实现事务
springAop与spring定时器
AOP的意思就是面向切面编程。本文主要是通过梳理JDK中自带的反射机制,实现 AOP动态代理模式,这也是Spring AOP 的实现原理
一个基于配置文件的Spring AOP的实现。实现了前置通知,后置通知,以及拦截器的功能,配置中有详细的注释。
顾名思义,Before Advice会在目标对象的方法执行之前被调用,您可以通过实现org.springframework.aop.MethodBeforeAdvice接口来实现Before Advice的逻辑,接口定义如下: java 代码 1. package org.springframework....
spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop
2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑实现 (需要知道原理的请看spring aop源码,此处不做赘述) 3、可在现有源码上快速进行功能扩展 4、spring boot,mybatis,druid,spring aop的使用
spring aop jar 包
java springAOP实现数据字典
Spring AOP 的实现例子(基于XML配置实现); 具体介绍看这里:https://blog.csdn.net/qq_22078107/article/details/85865543
博客《理解Spring AOP实现与思想》案例代码,对Java技术感兴趣的朋友可以关注一下我,我在csdn为您准备了很多Java干货。
spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...
描述一下Spring AOP? 在Spring AOP中关注点(concern)和横切关注点(cross-cutting concern)有什么不同? AOP有哪些可用的实现? Spring中有哪些不同的通知类型(advice types)? Spring AOP 代理是什么? 引介...
spring aop切面拦截指定类和方法实现流程日志跟踪 一般情况下,在不侵入业务代码的情况下,需要做流程日志跟踪是比较合理的 采用springaop切面思想
NULL 博文链接:https://donlianli.iteye.com/blog/1900885
使用Spring的AOP技术,实现日志记录功能。记录如下信息: 在哪个时间访问了哪个方法,方法传入了哪些参数