spring AOP 领悟

本文详细介绍了AOP(面向切面编程)的核心原理及其在Spring框架中的应用方式。重点讲解了AOP的基本概念,包括切面、连接点、通知、切入点等,并探讨了动态代理与Cglib实现的具体细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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() :获取代理对象本身;

参考文章:

Aop源码分析之如何实现功能增强

Spring中Adivisor和Aspect的区别(自我理解)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhousenshan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值