Spring AOP With AspectJ

一.AOP和拦截器

   某些情况下,AOP和拦截器包括Filter能够实现同样的功能,一般都是请求即controller层的操作,这三个执行顺序为Filter>Interceptor>AOP,当然这里面的区别我会重新写一篇文章讲解,这里面提一下就是想告诉大家,不一定要使用AOP,个人感觉用Filter和Interceptor实现的更方便简单一点。

二.AOP 准备

    在spring框架下,你还需要添加aspectjrt,aspectjweaver和cglib 的相关jar包,maven项目的pom.xml中可直接在maven公服获取配置。

    在spring-mvc.xml中配置aop,并添加<aop:aspectj-autoproxy /> 。

    对于aspect类,对类添加@Aspect和@Component即可。

三.Spring AOP简

    AOP这个概念看文档比较抽象,网上的举例子也基本上是操作日志这些,不过日志记录的确是一个非常形象的例子。说白了,当我们想对一些批量的方法进行一些补充操作,在service层和dao层,我们一般选择AOP。

    日志的例子,当我们dao层我们执行crud的时候同时想在数据库中生成一条日志记录,这时候日志的处理代码其实是一样的,我们可以提取出来。

    再比如,某些操作需要发短息通知用户(更改密码,账单到期等等),发短信的代码其实是一样的,就是一个手机号和短信内容。这时候我们用AOP就能解决,所有需要发短信的方法都可以用AOP来解决。好处是:只需要 一个地方维护代码,动态的决定哪些地方给用户发短信。

    一般用AOP的时候我们都是配合一些注解来完成的,注解的主要作用有两个方面:1.可以用来判断是否拦截该方法,2.传递一些aop方法中需要的参数或者变量值。

Glossory  of AOP:

    1.Pointcut: aop拦截的是哪些方法,必须要告诉aop方法,一般我们都是通过类似正则的表示,pointcut有不同的几种类型,通常我们见到的应该就是execution,其实目前我用的也就是execution,其他类型比如:within,this,args,target,@args,@target,@annotation...

      下面是pointcut的几个例子: pointcut的表达式可以通过'||','&&'和'!'连接

      @Pointcut("execution(pubic * *(..))")

      private void allOperation() {}

      @Pointcut("within(com.cnblog.service.User..") =>@Pointcut("execution(* com.cnblog.service.User.*(..))")

      private void userOperation() {}

      @Pointcut("allOperation() && userOperation() ")

      private void unionOperation() {}

2.Advice: Advice is associated with a pointcut expression, and runs before, after, or around method executions matched by the pointcut. The pointcut expression may be either a simple reference to a named pointcut, or a pointcut expression declared in place.

我们通常最简洁的用法就是@Around("execution(public *.update*(..))"),其实它等同于@Around(pointcut="execution(public *.update*(..))"),pointcut的值可以为上面我们定义的pointcut表达式的函数。下面主要介绍四种advice:

    Before:在拦截函数执行之前执行,一般数据权限或者用户验证的信息都是这样,类似Interceptor的prehandle。

     @Before("execution(public * * (..))")

      public void doCheck() {...}

    Around:around 是最通常用的,,因为可以before和after都融合,而且可以决定被拦截的方法什么时候执行,advice method的第一个参数必须是ProceedingJoinPoint.通过调用ProceedingJoinPoint的proceed方法就可以执行被拦截的函数。

      @Around("execution(public * * (..))")

      public Object doAround(ProceedingJoinPoint pjp ,..) {

          Object[] args = pjp.getArgs();

          ...

          return pjp.proceed(args);

      }

    After:在函数执行完之后执行,执行完包含被拦截函数返回值或者出现异常,一般情况我们是针对出现异常做一个记录等。

      @After("execution(public * * (..))")

      public void doFinal() {...}

   注:advice ordering:如果多个advices在同一个连接点执行,这时候就有一个执行顺序,一般情况下我们可以尽量避免,如果无法避免可以通过@Order(org.springframework.core.annotation.Order)来表示先后顺序。优先级越高,在"on  the way in"先执行,"on the way out"后执行.

4.Other keys: Introductions,perthis,PessimisticLockingFailureException(详情参照spring官方文档)

四.AOP的选择

    Spring AOP or AspectJ      ,Aspect language style ,@AspectJ or Spring xml style(aspect schema_based 这里面就不讲了,就是aop的xml配置)。

    1.Spring AOP  or full AspectJ

       spring aop 更简单,因为aspectj还需要引入compiler/weaver相关的jar 包。

       如果你的aop切入的是spring beans,可以直接使用spring  aop就可以了,如果你想拦截的对象不是spring容器管理的只能使用AspectJ,个人一直使用Aspectj,因                   为比较方便,如果用maven的话 就更简单了。

   2.个人建议直接使用@Aspect语法风格,使用spring xml配置很繁琐,而且容易遗漏。

五.AOP代理

  spring AOP使用JDK动态代理或者cglib来创建目标对象的代理,JDK动态代理会优先选择。

  默认情况下:如果被代理的目标对象至少实现了一个接口,那么这时候默认使用JDK动态代理,反之,则使用cglib。

  当然,你也可以强制使用cglib,如果你很偏爱它,不过在spring3.x你首先得提供cglib的相关jar包。然后需要在spring 中配置<aop:config proxy-target-class="true" />,to force CGLIB proxying when using @AspectJ autoproxy support ==> <aop:aspectj-autoproxy proxy-target-class="true" />

  理解AOP代理:

    一般object 调用:interface pojo  ,class SimplePojo implements pojo

public classMain {
    public  static voidmain(String[] args) {
      Pojo pojo = new SimplePojo();
    // this is a direct method call on the 'pojo' reference
    pojo.foo();
  }
}    

   我们稍微改变一下,当客户端只有一个代理的时候 ,如图: 

 

public classMain {
    public static voidmain(String[] args) {
        ProxyFactory factory = newProxyFactory(newSimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(newRetryAdvice());
        Pojo pojo = (Pojo) factory.getProxy();
        // this is a method call on the proxy!
        pojo.foo();
    }
}            

  

原文地址:https://www.cnblogs.com/wangkeustc/p/4718154.html