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------------------------------