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------------------------------
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号