深入解读spring4的面向切面编程AOP

读了<<sping in action 4>>中的面向切面编程一章后,觉得有必要记录一下,自己对面向切面编程的理解,必定概念是概念,理解是理解;

为什么会有面向切面编程:主要是为了解脱业务主要功能模块,叫你的业务功能更专一,更简单,写起来更方便;

对于面向对象编程的开发人员,都知道,如果有重用或者通用的功能,我们想到的很有可能是继承或者委托,但是这种方式如果大量存在,则会使得整个应用体系变的非常脆弱,牵一发而动全身,因为有一个共同的基类;切面提供了取代继承和委托的另一种可选方案。

在使用切面编程时,我们任然在一个地方定义通用功能,但是可以通过声明的方式定义这个功能以何种方式在何处应用,而对于应用自身的类不受通用功能的影响;

面向切面编程的优点:每个通用功能都是在一处定义,而不是分散到多处代码中;其次就是服务模块更简洁,只负责业务服务,而对于次要的通用的功能被转移到切面中了。

AOP专业术语介绍:

通知(advice):定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题,切面可以应用的5种类型的通知;

   1)前置通知(before):在目标方法被调用之前调用通知定义的功能;

   2)后置通知(after):在目标方法被调用完成之后调用通知定义的功能;

   3)环绕通知(around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行通知定义的行为;

   4)返回通知(After-returning):被调用方法成功执行完成后调用通知定义的方法;

   5)异常通知(After-throwing):被调用方法执行过程中抛出异常后调用通知定义的方法;

重点理解:通知定义了切面的功能和执行切面的时间;即要干什么如统计日志,开启事务,安全认证等,执行切面的时间表示了是在方法执行之前还是之后,还是之前和之后都有,或者是方法正常返回或者出异常之后,分别采用不同的注解来完成。

连接点(Join point):我们的应用可能也有数以千计的时机应用通知。这些时机被称为连接点。连接点是再应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至是修改一个字段时,切面代码可以利用这些点插入到应用的正常执行流程之中,并添加新的行为;

重点理解:连接点可以被看成是切面可以作用的所有点,如果切面是面向方法的,那么所有方法就是连接点,如果切面是面向属性的,那么所有对象中的属性就是连接点,若果切面是面向对象构造的,那么所有对象的构造过程都是连接点;如开发中用到最多的spring切面都是面向对象的,则应用中的所有业务方法都是切面的连接点。

切点(Pointcut):规定了匹配通知所要织入的一个或者多个连接点,通常通过明确的类和方法名称,或者利用正则表达式来选择具体的连接点来作为切点;

重点理解:并不是所有的连接点,我们都想要去执行通知定义的功能,而对于部分不需要去执行通知的连接点,我们需要通过切点的定义来过滤掉不需要的部分连接点,剩下的就是要添加额外功能,执行通知的连接点,被称为切点。

切面(Aspect):是通知和切点的结合。通知和切点共同定义了切面的全部内容--它是什么(通知),在何时(通知)和何处(切点)完成其功能。

引入(introduction):向现有类添加新方法或者属性,从而可以在无需修改现有类的情况下,让他们具有新的行为和状态。

织入(Weaving):是把切面应用到目标对象并创建新的代理对象的过程。在目标对象的生命周期里有多个点可以进行织入:编译期,类加载期,运行期。

spring提供了4种类型的AOP支持;

基于代理的经典SpringAop;

纯POJO切面;

@Aspectj注解驱动的切面

注入式Aspectj切面;

注:前三种都是SpringAOP实现的变体,SpringAop构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法拦截。

springAOP的三个关键知识点:

1)Spring通知是java编写的;

2)Spring在运行时通知对象;

3)spring只支持方法级别的链接点;

如何编写切点来选择连接点?

spring借助AspectJ的切点表达式语言来定义Spring切面;

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

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

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

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

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

@target:限制连接点匹配特定的执行对象,这些对象对于的类要具有指定类型的注解

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

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

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

编写切点:

execution(* concert.Performance.perform(..)):表面切点为concert包下的Performance对象的perform方法,方法的返回类型可以是任意类型,方法的参数可以是任意类型;

execution(* concert.Performance.perform(..))&&within(concert.*):表明只有在concert包下的perform方法接受通知功能;

使用注解创建切面;通过在普通java对象添加@Aspect注解来创建切面;在额外功能方法上添加注解来实现在何时何处执行切面功能;

@Aspect

public class Audience{

    @Before("execution(* * concert.Performance.perform(..))")

    public void executeAopOnMethodBefore(){}

    @afterReturning("execution(* * concert.Performance.perform(..))")

    public void executeAopOnMethodAfterReturn(){}


}


通过@Pointcut来简化开发:

@Aspect

public class Audience{

@Pointcut("execution(* * concert.Performance.perform(..))")

 public void performance(){}

    @Before("performance()")

    public void executeAopOnMethodBefore(){}

    @afterReturning("performance()")

    public void executeAopOnMethodAfterReturn(){} 

   @Around("performance()")

    public void executeAopOnMethod(ProceedingJoinPoint jp){

          //方法前执行

         jp.proceed();

         //方法后执行

       }

}

开启AOP;

1)如果是通过javaConfig对象作为配置文件来开发项目,则在配置文件对象中添加注解@EnableAspectJAutoProxy,并将切面对象自动注入;

2)如果通过xml文件的配置文件来启动项目,则应该在xml文件中配置AOP:<aop:aspectj-autoproxy/>并将切面对象也以bean的形式配置进来,切面方可起作用。

---------------------------------------springAOP进阶--------------------------------------

处理通知中的参数;传递参数给方法;已实现对象之外的额外功能;

execution(* * concert.Performance.perform(arg_types))&&args(arg)

在切点表达式中声明参数,这个参数传入到通知方法中。

@Aspect

public class Audience{

@Pointcut(execution(* * concert.Performance.perform(arg_types))&&args(arg)")

   public void performance(arg_types arg){   

}

    @Before("performance(arg)")

    public void executeAopOnMethodBefore(arg_types arg){

     sout(arg);

     }

}


通过注解引入新的功能:在spring中,切面只是实现了它们所包装bean相同接口的代理。如果除了实现这些接口,代理也能暴露新接口的话,切面所通知的bean看起来像是实现了新的接口,即便底层实现类并没有实现这些接口也无所谓;调用者即可以调用现有对象的方法,也可以调用被引入的方法;当调用的是现有的方法,则代理对象将调用给了被通知的bean.如果调用的是引入接口的方法,代理会把此调用委托给实现了新接口的某个其他对象。实际上一个bean的实现被拆分到了多个类中。

借助AOP的引入功能,我们可以建立新的切面如:

@Aspect

public class EncoreableIntroducer{

   @DeclareParents(value="concert.Performance+",defaultImpl=DefaultEncoreable.class)

    public static Encoreable encoreable;

}

该切面通过@DeclareParents注解将Encoreable接口引入到Performance bean中。

其中@DeclareParents注解的三部分;

value指定了那种类型的bean要引入该接口,+号表示是所有bean的子类,而不是bean本身;

defaultImpl属性指定了为引入功能提供实现的类;

@DeclareParents注解所标注的静态属性指明了要引入的接口。


当spring发现一个bean使用了@Aspect注解时,就会创建一个代理,然后将调用委托给被代理的bean或者被引入的实现,这取决于调用的方法属于被代理的bean还是属于被引入的接口。



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值