面向切面的spring

来源:互联网 发布:淘宝店标,店铺说明 编辑:程序博客网 时间:2024/04/30 08:07

       在软件开发中,分布于应用多处的功能被称为横切关注点。将这些横切关注点和业务逻辑分离是面向切面锁要解决的问题。横切关注点可以被模块化为特殊的类,这些类就叫做切面。这样做的好处:每个关注点集中于一处,而不是分散到多出代码中。服务模块更简洁,它们只要关心核心功能就行了,其他转移到切面中去了。

    

1.1定义AOP术语

     描述aop的常用术语有通知(advice)、切点(pointcut)、和连接点(join point)。 


通知:

      通知定义了切面是什么以及何时执行,有5中通知类型。

      1.Before:在方法执行前调用通知。

      2.After:在方法执行后调用通知,不管方法执行是否成功。

      3.After-returning:在方法成功执行后调用通知。

      4.After-throwing:在方法抛出异常时调用。

      5.Around:通知包含了被通知的方法,再被通知的方法调用之前和之后执行相应的自定义工作。

连接点:连接点就是应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、调用方法后、抛出异常时等等,切面代码可以利用这些点插入到应用程序的正常流程中,并添加新的行为。


切点:如果通知定义了什么和何时,那么切点就定义了何处。切点有助于缩小连接点的范围,因为一个切面不需要通知所有的连接点。


切面(Aspect):通知和切点的结合。它们定义了切面是什么,在何时何处执行。


引入(Introduction):引入允许向现有的类添加新方法或属性。

织入(weaving):织入是将切面应用到目标对象来生成心得代理对象的过程。切面在指定的连接点中被织入目标对象。目标对象的生命周期中有多个点可以进行织入。

1.编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器,AspectJ的织入编译器就是这个时候织入的。

2.类加载期:切面在类加载到jvm是被织入。这种方式需要特殊的类加载器,它可以再目标类被引入应用之前加强目标类的字节码。AspectJ的LTW就是这种方式织入的。

3.运行期:切面在应用运行到某一时刻时被织入。一般情况下,在织入切面时,AOP容器会为目标对象创建一个代理对象。Spring AOP就是这种方式织入的。


1.2 Spring对AOP的支持

      并不是所有的aop框架都是一样的,它们在连接点模型上有强弱之分。有三个AOP框架:AspectJ,JBoss AOP,Spring AOP。

spring提供4中具有特殊的aop支持:

1.基于代理的经典AOP。

2.@AspectJ注解驱动的切面。

3.纯POJO切面。

4.注入式AspectJ切面(适合spring个版本)

      前三种方法都是基于代理的aop的变种,spring对aop的支持局限于方法的拦截。如果对aop的需求超过了对简单方法的拦截(比如对构造方法或属性拦截),那么需要在AspectJ里实现切面,利用依赖注入把Spring Bean注入到切面中。



2.使用切点选择连接点

      spring支持的AspectJ切点指示器。

args()---------限制连接点匹配参数为指定类型的执行方法。

@args()---- 限制连接点匹配参数为指定注解标注的执行方法。

execution()  用于匹配时连接点的执行方法

this()--------- 限制连接点匹配AOP代理的Bean的引用为指定类型的类

target()-------限制连接点匹配目标对象为指定类型的类

@target()     限制连接点匹配特定的执行对象,这些对象对应的类要有指定的注解

within()         限制连接点匹配指定的类型

@within()      限制连接点匹配注解所标注的类型

@annotation 限制匹配带有指定注解的连接点

      在Spring使用其他AspectJ指示器时会报illegalArgumentException。只有execution是唯一的执行匹配,其他都是限制匹配。


2.1编写切点

execution(* com.xxx.A.get(..))
上面第一个*表示返回类型,*表示不关心返回类型,随便什么返回类型都可以。然后是类的全限定名和方法名。(..)表示使用任意参数都可以,就是说所有的get()方法。
execution(xxx) && within(xxx) || execution(xxx) && arg(xxx) ||!execution(xxx) 

2.2使用spring的bean指示器

      这个指示器允许在切点表达式中使用Bean的id来识别Bean。

execution(xxx) && bean(id)

3 在xml中声明切面

<aop:advisor>:定义AOP通知器

<aop:after>:定义AOP后置通知

<aop:after-returning>:定义AOP after-returning通知

<aop:after-throwing>:定义AOP after-throwing通知

<aop:around>:定义AOP环绕通知

<aop:aspect>:定义切面

<aop:aspectj-autoproxy>:启动@AspectJ注解驱动的切面

<aop:before>:定义前置通知

<aop:config>:顶层的aop配置元素,大多数<aop:*>都在这里面

<aop:declear-parents>:为被通知的对象引入额外的接口,并透明的实现。

<aop:pointcut>:定义切点

<aop:config>   <aop:aspect id="bean的id">//定义切面        <aop:pointcut id="切点id" expression="execution()"/>//定义切点        <aop:before pointcut-ref="上面的切点id" method="bean里面的方法名"/>//定义前置通知    </aop:aspect></aop:config>
如果pointcut想被多个切面引用,就把pointcut定义在config中。


3.1 声明环绕通知

<aop:around  pointcut-ref="" method=""/>
      环绕通知就是把前置通知和后置通知合起来变为一个方法。如果前置通知和后置通知有联系,那么可以用环绕通知来实现,环绕通知的方法参数要有被通知的对象,这样可以调用被通知的方法。


3.2为通知传递参数

 

<aop:before pointcut-ref="" method="" arg-names="name" />

3.3 通过切面引入新功能

<aop:aspect>   <aop:declear-parents    types-matching=""//匹配类   implement-interface=""//实现的接口   default-impl=""//接口的实现类   delegate-ref=""//引入接口实现类的Bean  id和上面的区别就是它是引用外部的一个Bean/></aop:aspect>

4.注解切面

@AspectJ//定义切面class A{@Pointcut("execution()")//定义切点  public void a(){} @Before("a()") public void before(){System.out.println("before")}  @AfterReturning("a()")  public void afterReturning(){System.out.pringln("afterReturning")}}

        然后要在xml中加上<aop:aspectj-autoproxy/>,这个元素仅仅使用@AspectJ注解作为指引来创建基于代理的切面。本质还是spring风格的切面。

        <aop:aspect>和@AspectJ注解都是把一个POJO转变为一个切面的有效方式。<aop:aspect>可以引用任意一个Bean,而注解就要实现一个类。


4.1注解环绕通知

@Around("a()")public void around(ProceedingJoinPoint a){    a.proceed();}

@DeclearParents(value=""defaultImpl="")private A a;


0 0
原创粉丝点击