Spring Aop学习

来源:互联网 发布:关于股票信息软件 编辑:程序博客网 时间:2024/06/07 04:26

《Spring in Action》的持续学习中,来到了spring aop,以下是一个简单的梳理:

AOP术语

通知(advice):切面的工作。
切点(pointcut)
连接点(join point):应用执行过程中能够插入切面的一个点。这个点可以使调用方法时、抛出异常时、甚至修改一个字短时。
切面(aspect):通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。
织入(weaving):spring aop是在运行时通过动态代理织入的。

五种通知
spring切面可以应用五种类型的通知:

  • 前置通知(before):在目标方法被调用之前调用此通知功能。
  • 后置通知(after):在目标方法完成之后调用通知,此时不关心方法的输出是什么。
  • 返回通知(after-returning):在目标方法成功执行之后调用通知。
  • 异常通知(after-throwing):在目标方法抛出异常后调用通知。
  • 环绕通知(around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
    注意:应用顺序:环绕通知->环绕通知内应用before前置通知->环绕通知全体完毕后应用后置通知。如果环绕通知内有异常,则需要catch,否则应用完after-throwing异常通知后,将会抛出异常;若在环绕通知内已catch,将不再调用异常通知。如果异常通知调用,返回通知自然不用。

注意:应用顺序:环绕通知->环绕通知内应用before前置通知->环绕通知全体完毕后应用后置通知。如果环绕通知内有异常,则需要catch,否则应用完after-throwing异常通知后,将会抛出异常;若在环绕通知内已catch,将不再调用异常通知。如果异常通知调用,返回通知自然不用。


spring借鉴了aspectj的切面,以提供注解驱动的AOP,但本质上依然是基于动态代理的,所以只支持方法级别的连接点。sprign仅支持AspectJ切点指示器的一个子集。

在spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgument-Exception异常。
原理
通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。
spring的切面由包裹了目标对象的代理类实现。代理类处理方法的调用,执行额外的切面逻辑,并调用目标方法


bean( )指示器:在切点表达式中使用bean的Id来表示bean,使用beanID或bean名称作为参数来限制切点只匹配特定的bean。


使用注解创建切面

AspectJ提供了五个注解来定义通知:

可以使用@Pointcut注解定义命名切点。
@Pointcut注解能够在一个@AspectJ切面内定义可重用的切点。

启用自动代理功能:
javaConfig:@EnableAspectJAutoProxy
xml:<aop:aspectj-autoproxy>
不管是javaConfig还是xml,AspectJ自动代理都会为使用@Aspect注解的bean创建一个代理,这个代理会围绕着所有该切面的切点所匹配的bean


切面可以访问和使用传递给被通知方法的参数

在切点表达式中使用arg()切点指示器限定匹配。
切点定义中的参数与切点方法中的参数名称一致,通过通知注解和命名切点定义通知,就完成了从命名切点到通知方法的参数转移。

例:

在XML中声明切面

如果没有源码,或者不想将AspectJ注解放进你的代码之中,spring为切面提供了另外一种可选方案:在spring XML配置文件中声明切面。

Spring AOP

spring的aop命名空间中,提供了多个配置元素用来在xml中声明切面。

AOP配置元素 用途 <aop:advisor> 定义AOP通知器 <aop:after> 定义AOP后置通知 <aop:after-returning> 定义AOP返回通知 <aop:after-throwing> 定义AOP异常通知 <aop:around> 定义AOP环绕通知 <aop:aspect> 定义一个切面 <aop:aspectj-autoproxy> 启用@AspectJ注解驱动的切面 <aop:before> 定义一个AOP前置通知 <aop:config> 顶层AOP配置元素。大多数的<aop:*>元素必须包含在次元素内。 <aop:declare-parents> 以透明的方式为被通知的对象引入额外的接口 <aop:pointcut> 定义一个切点

定义前置通知&后置通知&环绕通知

定义前置通知:
<aop:before pointcut="" method="">
<aop:before pointcut-ref="" method="">

可重用切点:<aop:pointcut id="" expression="AspectJ切点表达式,可带参数(args(参数名))">,定义在<aop:aspect>内,只为当前切面的通知所引用。如果想被多个切面引用,声明在<aop:config>内。

定义后置通知:
<aop:after pointcut="" method="">
<aop:after pointcut-ref="" method="">
定义环绕通知:
<aop:around pointcut="" method="">
<aop:around pointcut-ref="" method="">

为什么在xml中需要环绕通知?
当需要在前置通知、后置通知中共享变量的时候,一般来说可以借助一个成员变量来实现。但是,spring中大部分bean是单例的,多线程下是不安全的。环绕通知一般可以完成前置、后置通知的功能,将通知逻辑在一个方法内实现,所以不需要成员变量来保存状态。
为环绕通知传递参数
在引用的或者属性pointcut中,在expression参数里带上“and args(参数名)”即可。

注入AspectJ切面

当spring aop不能满足要求时,如连接点的细粒度,可以使用AspectJ切面。

对于大部分功能来讲,AspectJ切面与Spring是相互独立的。虽然它们可以织入到任意的Java应用中,这也包括了Spring应用,但是在应用AspectJ切面时几乎不会涉及到Spring。但是精心设计且有意义的切面很可能依赖其他类来完成它们的工作。如果在执行通知时,切面依赖于一个或多个类,我们可以在切面内部实例化这些协作的对象。但更好的方式是,我们可以借助Spring的依赖注入把bean装配进AspectJ切面中。

首先必须明确一点,AspectJ切面根本不需要Spring就可以织入应用中。
如果想使用spring的依赖注入为AspectJ切面注入协作者,那就需要在spring配置中把切面声明为一个spring配置中的<bean>

注意:spring bean由spring容器初始化,但是AspectJ切面是由AspectJ在运行期创建的。等到Spring为AspectJ切面注入协作者时,AspectJ切面已经被实例化了。所以,我们需要一种方式为Spring获得已经由AspectJ创建的切面实例的句柄,从而可以实现注入。幸好,所有的AspectJ切面都提供了一个静态的aspectOf()方法,该方法返回切面的一个单例。所以为了获得切面的实例,必须在<bean>中使用factory-method来调用aspectOf()方法而不是简单调用构造器方法:<bean id="" class="" factory-method="aspectOf">

结语

虽然都是《Spring in Action》一书中关于spring aop的内容,说是梳理,也只是照搬照抄,按照自己理解的内容稍稍整理下,不喜勿喷~也望各位大佬们多多提点~~很愿意学习

原创粉丝点击