AOP的实现

  AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。

  AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理(编译时增强)和动态代理(运行时增强),静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。

(1)使用AspectJ的编译时增强实现AOP

  所谓的静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。

  举个实例的例子来说。首先我们有一个普通的Hello类
  public class Hello {
    public void sayHello() {
      System.out.println("hello");
    }
    public static void main(String[] args) {
      Hello h = new Hello();
      h.sayHello();
    }
  }

  使用AspectJ编写一个Aspect
    public aspect TxAspect {
      void around():call(void Hello.sayHello()){
        System.out.println("开始事务 ...");
        proceed();
        System.out.println("事务结束 ...");
      }
     }

  编译完成之后再运行这个Hello类,可以看到以下输出
    开始事务 ...
    hello
    事务结束 ...

  很显然,AOP已经生效了,那么究竟AspectJ是如何在没有修改Hello类的情况下实现代码增强的?
  查看一下编译后的Hello.class
    public class Hello {
      public Hello() {
      }
      public void sayHello() {
        System.out.println("hello");
      }
      public static void main(String[] args) {
        Hello h = new Hello();
          sayHello_aroundBody1$advice(h, TxAspect.aspectOf(), (AroundClosure)null);
      }
    }

  如此,proceed()方法就是回调执行被代理类中的方法。

(2)使用Spring AOP

  Spring AOP使用的动态代理,动态代理就是说AOP不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。需导入两个jar包:cglib.jar、asm.jar。

  Spring AOP中的动态代理主要有两种方式:jdk动态代理 、cglib动态代理。jdk动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。jdk动态代理的核心InvocationHandler接口 、Proxy类。

  当目标类没有实现接口,那么Spring AOP会选择使用cglib来动态代理目标类。cglib(Code Generation Library)是一个代码生成的类库,可以在运行时动态的生成某个类的子类,cglib是通过继承的方式做的动态代理,所以若某个类被标记为final,那么它就无法使用cglib做动态代理的。

  定义一个接口
  public interface Person {
    String sayHello(String name);
  }

  实现类
  @Component
  public class Chinese implements Person {
    @Override
    public String sayHello(String name) {
      System.out.println("-- sayHello() --");
      return name + " hello, AOP";
    }
  }

   

  实现类

  public class MyInvocationHandler implements InvocationHandler {
     private Object target;
     MyInvocationHandler() {
      super();
    }
    MyInvocationHandler(Object target) {
      super();
      this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // 程序执行前加入逻辑,MethodBeforeAdviceInterceptor
      System.out.println("before-----------------------------");
      // 程序执行
      Object result = method.invoke(target, args);
      // 程序执行后加入逻辑,MethodAfterAdviceInterceptor
      System.out.println("after------------------------------");
      return result;
    }
  }

  测试类 

  public class Test {
  /**
  * JDK动态代理测试类
  */
  public static void main(String[] args) {
    Chinese chinese= new Chinese();
    MyInvocationHandler mih = new MyInvocationHandler(chinese);
    Class<?> cls = chinese.getClass();
    /**
    * loader 类加载器
    * interfaces 实现接口
    * h InvocationHandler
    */
    Person p = (Person)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
    System.out.println(p.sayHello("张三"));
    }
  }

  输出

  before-----------------------------

  张三 hello, AOP

  after------------------------------

  

  我们再来看看不是用接口的情况,修改Chinese类

  实现类
  @Component
  public class Chinese {
    public String sayHello(String name) {
      System.out.println("-- sayHello() --");
      return name + " hello, AOP";
    }
  }

   

  实现类 

  public class CglibProxy implements MethodInterceptor {
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      System.out.println("before-------------");
      // 执行目标类add方法
      proxy.invokeSuper(object, args);
      System.out.println("after--------------");
      return null;
    }
  }

  目标类的工厂Factory类

  public class Factory {
    //获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
    public static Base getInstance(CglibProxy proxy) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(Chinese.class);
      //回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
      enhancer.setCallback(proxy);
      // 此刻,base不是单纯的目标类,而是增强过的目标类
      Chinese chinese = (Chinese) enhancer.create();
      return chinese;
    }
  }

  测试类  

  public class Test {
    public static void main(String[] args) {
      CglibProxy proxy = new CglibProxy();
      // base为生成的增强过的目标类
      Chinese chinese = Factory.getInstance(proxy);
      System.out.println(chinese.sayHello("张三"));
    }
  }

  输出

  before-----------------------------

  张三 hello, AOP

  after------------------------------

猜你喜欢

转载自www.cnblogs.com/lhns/p/9003749.html