一、Aop原理
Aop的核心原理概括起来就是代理和拦截。代理对象生成之后,当我们调用目标对象被代理的方法时,就会触发拦截器的拦截功能,从而实现增强目标对象功能的作用。拦截器对目标对象方法进行拦截的方式是回调,比如使用Jdk动态代理生成的对象都会实现InvocationHandler接口,那么就需要在回调invoke方法中实现拦截,即增强,同理如果使用Cglib的方式生成代理对象,那么实现拦截功能的就是回调方法就是intercept方法。看到此处我们会发现其实拦截器和代理对象是同一个东西,或者说代理对象中的回调方法实现了目标对象增强功能。
1、详见:java进阶(七):详解JAVA代理
2、主要是Proxy 与 InvocationHandle r接口
(二)Cglib 实现
1、主要是 Enhancer 和 MethodInterceptor 接口
二、概念
通常aspect+pointcut用于日志记录和一些通用方法操作,advisor+pointcut用于事务管理,Joinpoint通常用于方法中的参数
1)切面(aspect):用来切插业务方法的类。
2)连接点(joinpoint):是切面类和业务类的连接点,其实就是封装了业务方法的一些基本属性,作为通知的参数来解析。
3)通知(advice):在切面类中,声明对业务方法做额外处理的方法。
4)切入点(pointcut):业务类中指定的方法,作为切面切入的点。其实就是指定某个方法作为切面切的地方。
5)目标对象(target object):被代理对象。
6)AOP代理(aop proxy):代理对象。
7)前置通知(before advice):在切入点之前执行。
8)后置通知(after returning advice):在切入点执行完成后,执行通知。
9)环绕通知(around advice):包围切入点,调用方法前后完成自定义行为。
10、异常通知(after throwing advice):在切入点抛出异常后,执行通知。
区别:— 方/切 面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
— 连接点/织入点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
— 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。
— 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
所以“<aop:aspect>”实际上是定义横切逻辑,就是在连接点上做什么,“<aop:advisor>”则定义了在哪些连接点应用什么<aop:aspect>。Spring这样做的好处就是可以让多个横切逻辑(即<aop:aspect>定义的)多次使用,提供可重用性。
1、Adivisor是一种特殊的Aspect,Advisor代表spring中的Aspect
2、区别:advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice
示意图如上:
我们平常的程序执行可以看成是横向的箭头,具有线性执行的特性;蓝色的小方框可以堪称是一个个线性执行中打断进程的切入点PointCut;有个Pointcut,那么就可以在切入点上面执行相关的逻辑,罗技分为两种,一种是adivisor,还有一种是Aspect;
其中Advisor如同上图左边的小红圈,只能够有一个advice,是一个点逻辑;右边的向下的箭头可以看作是Aspect,其可以拥有执行多个逻辑,是一个面逻辑;
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。前面说过Spring使用动态代理默认使用jdk代理,高版本的Spring会自动选择是使用动态代理还是CGLIB生成代理内容,当然我们也可以强制使用CGLIB生成代理,那就是<aop:config>里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false或者这个属性被省略,那么基于接口的代理将起作用增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被示例如下,配制了多个pointcut:
<bean id="logAspect" class="com.abc.aspect.LogAspect">
<property name="logBiz" ref="logBiz" />
</bean>
<aop:config>
<aop:pointcut id="pointcut_add" expression="execution(* com.abc..biz..*.add*(..))"/>
<aop:pointcut id="pointcut_update" expression="execution(* com.abc..biz..*.update*(..))"/>
<aop:pointcut id="pointcut_delete" expression="execution(* com.abc..biz..*.delete*(..))"/>
<aop:aspect ref="logAspect">
<aop:after pointcut-ref="pointcut_add" method="log" />
<aop:after pointcut-ref="pointcut_update" method="log" />
<aop:after pointcut-ref="pointcut_delete" method="log" />
</aop:aspect>
</aop:config>
expression说明:
<aop:pointcut id="serviceMethod" expression="execution(* *..*Service.*(..))" />
第一个* 表示任意返回值类型
第二个* 表示以任意名字开头的package. 如 com.xx.
第三个* 表示以任意名字开头的class的类名 如TestService
第四个* 表示 通配 *service下的任意class
最后二个.. 表示通配 方法可以有0个或多个参数
其它示例
execution(* com.aptech.jb.epet.dao.hibimpl.*.*(..))
这样写应该就可以了
这是com.aptech.jb.epet.dao.hibimpl 包下所有的类的所有方法。。
第一个*代表所有的返回值类型
第二个*代表所有的类
第三个*代表类所有方法
最后一个..代表所有的参数。
拦截方法中常见用法
java.lang.Object[] getArgs():获取连接点方法运行时的入参列表; getArgs[0]通过反序列化可以得到对象。
Signature getSignature() :获取连接点的方法签名对象;
java.lang.Object getTarget() :获取连接点所在的目标对象;
java.lang.Object getThis() :获取代理对象本身;
参考文章:
Spring中Adivisor和Aspect的区别(自我理解)