本篇开始Aop的相关的内容,aop的底层使用到了动态代理的,我们针对一个方法可以配置多个切面,也就实现了多重代理。本篇先不看源码,从开发者的角度观望如何实现多重代理。

一,代理模式

代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问。
代理模式的主要角色如下。

  1. 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  2. 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  3. 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

image.png
在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。
根据代理的创建时期,代理模式分为静态代理和动态代理。

  • 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
  • 动态:在程序运行时,运用反射机制动态创建而成。

    1.JDK的动态代理

动态代理

  1. 特点:字节码随用随修改,随用随加载
  2. 作用:在不修改源码的基础上在运行时动态的对方法进行增强
  3. 分类:
    1. 基于接口的动态代理
    2. 基于子类的动态代理
  4. 基于接口的动态代理
    1. 涉及的类:Proxy
    2. 提供者:JDK官方
  5. 如何创建代理对象
    1. 使用Proxy类的**newProxyInstance()**
  6. 创建代理对象的要求
    1. 被代理类最少实现一个接口,如果没有则不能使用
  7. **newProxyInstance()**的参数
    1. ClassLoader:类加载器,用于加载代理对象字节码文件;和被代理对象使用相同的类加载器。
    2. Class[]:字节码数组,用于让代理对象和被代理对象实现相同方法的。
    3. InvocationHandler:用于提供增强的代码,他是让我们自定义如何代理,我们一般都是写一个该接口的实现类。
  8. 简单的实现

    1. public class Test1 {
    2. @Test
    3. public void test1(){
    4. //被代理类对象要声明为最终的
    5. final Producer producer=new Producer();
    6. //代理对象和被代理类对象要实现同一个接口
    7. IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
    8. producer.getClass().getInterfaces(),
    9. new InvocationHandler() {
    10. /**
    11. * 作用:执行被代理对象的任何接口方法都会经过该方法
    12. * 方法参数的含义
    13. * @param proxy 代理对象的引用
    14. * 1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName()。
    15. * 2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。
    16. * @param method 当前执行的方法
    17. * @param args 当前执行方法所需的参数
    18. * @return 和被代理对象方法相同的返回值
    19. * @throws Throwable
    20. */
    21. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    22. Object value=null;
    23. //获取方法执行的参数
    24. //判断当前方法是不是销售
    25. if ("saleProduct".equals(method.getName())){
    26. Float money= (Float) args[0];
    27. //两个参数:被代理类对象,方法增强的参数
    28. value=method.invoke(producer,money*0.8f);
    29. }
    30. return value;
    31. }
    32. });
    33. proxyProducer.saleProduct(10000f);
    34. }
    35. }

    ```java package com.es.java1;

/**

  • 一个生产者 */ public class Producer implements IProducer{

    /**

    • 销售
    • @param money */ public void saleProduct(float money){ System.out.println(“销售产品,并拿到钱:”+money); }

      /**

    • 售后
    • @param money */ public void afterService(float money){ System.out.println(“提供售后服务,并拿到钱:”+money); } }

/**

  • 对生产厂家要求的接口 */ public interface IProducer {

    /**

    • 销售
    • @param money */ public void saleProduct(float money);

      /**

    • 售后
    • @param money */ public void afterService(float money); } ```

      2.cglib动态代理

    基于子类的动态代理

  1. 涉及的类:Enhancer ,提供者:第方cglib库
  2. 如何创建代理对象: 使用Enhancer类中的create方法
  3. 创建代理对象的要求: 被代理类是最终类
  4. create方法的参数:
    1. Class:字节码 :它是用于指定被代理对象的字节码。
    2. Callback:用于提供增强的代码 :它是让我们写如何代理。我们一般都是些一个该接口的实现类。 我们一般写的都是该接口的子接口实现类:**MethodInterceptor**
  5. 简单的实现
    1. /**
    2. * @author yinhuidong
    3. * @createTime 2020-03-02-1:08
    4. */
    5. public class Test4 {
    6. @Test
    7. public void test() {
    8. final Producer producer = new Producer();
    9. Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
    10. /**
    11. * 执行被代理对象的任何方法都会经过该方法
    12. * @param proxy
    13. * @param method
    14. * @param args
    15. * 以上个参数和基于接口的动态代理中invoke方法的参数是一样的
    16. * @param methodProxy :当前执行方法的代理对象
    17. * @return
    18. * @throws Throwable
    19. */
    20. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    21. //提供增强的代码
    22. Object returnValue = null;
    23. //1.获取方法执行的参数
    24. Float money = (Float) args[0];
    25. //2.判断当前方法是不是销售
    26. if ("saleProduct".equals(method.getName())) {
    27. returnValue = method.invoke(producer, money * 0.8f);
    28. }
    29. return returnValue;
    30. }
    31. });
    32. cglibProducer.saleProduct(12000f);
    33. }
    34. }

    二,多重代理

    1.基于责任链模式的多重代理

    1.1 被代理的方法

    ```java public interface Animal { void eat(String food);}

public class Cat implements Animal{

@Override public void eat(String food) { System.out.println(“猫吃”+food+”!”); } }

  1. <a name="Iyv5A"></a>
  2. ### 1.2封装目标对象的目标方法
  3. ```java
  4. public class TargetMethod {
  5. /**
  6. * 目标对象
  7. */
  8. private Object target;
  9. /**
  10. * 目标方法
  11. */
  12. private Method method;
  13. /**
  14. * 方法参数
  15. */
  16. private Object[] args;
  17. public TargetMethod(Object target, Method method, Object[] args) {
  18. this.target = target;
  19. this.method = method;
  20. this.args = args;
  21. }
  22. public Object getTarget() {
  23. return target;
  24. }
  25. public void setTarget(Object target) {
  26. this.target = target;
  27. }
  28. public Method getMethod() {
  29. return method;
  30. }
  31. public void setMethod(Method method) {
  32. this.method = method;
  33. }
  34. public Object[] getArgs() {
  35. return args;
  36. }
  37. public void setArgs(Object[] args) {
  38. this.args = args;
  39. }
  40. }

1.3 抽象的责任链节点和驱动责任链往下执行的头节点

public abstract class AbstractSlot {

   TargetMethod targetMethod;

   AbstractSlot next;

   abstract Object invoke(TargetMethod targetMethod);

   private boolean hasNextSlot() {
      return next != null;
   }

   public Object proceed(TargetMethod targetMethod) throws Exception {
      return hasNextSlot() ?
            next.invoke(targetMethod) :
            targetMethod.getMethod()
                  .invoke(
                        targetMethod.getTarget(),
                        targetMethod.getArgs()
                  );
   }

   public AbstractSlot(TargetMethod targetMethod, AbstractSlot next) {
      this.targetMethod = targetMethod;
      this.next = next;
   }

   public TargetMethod getTargetMethod() {
      return targetMethod;
   }

   public void setTargetMethod(TargetMethod targetMethod) {
      this.targetMethod = targetMethod;
   }

   public AbstractSlot getNext() {
      return next;
   }

   public void setNext(AbstractSlot next) {
      this.next = next;
   }

   public AbstractSlot() {
   }

   public static class Head extends AbstractSlot{

      @Override
      Object invoke(TargetMethod targetMethod) {
         return null;
      }
   }


}

1.4 对方法增强的类

public class JdkDynamic implements InvocationHandler {

   Object target ;

   AbstractSlot head;

   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      return head.proceed(new TargetMethod(
            target,method,args
      ));
   }

   public Object getProxy(){
      return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
      );
   }

   public JdkDynamic(Object target, AbstractSlot head) {
      this.target = target;
      this.head = head;
   }
}

1.5测试类

public class Main {

   public static void main(String[] args) {

      AbstractSlot.Head head = new AbstractSlot.Head();
      AbstractSlot first = new First();
      AbstractSlot second=new Second();
      first.setNext(second);
      head.setNext(first);

      JdkDynamic jdkDynamic = new JdkDynamic(new Cat(),head);
      Animal proxy = (Animal) jdkDynamic.getProxy();
      proxy.eat("事物");

   }



   private static class First extends AbstractSlot{

      @Override
      Object invoke(TargetMethod targetMethod) {

         Object result = null;
         System.out.println("增强逻辑");
         try {
            result= proceed(targetMethod);
         } catch (Exception e) {
            e.printStackTrace();
         }
         System.out.println("增强逻辑");
         return result;
      }
   }

   private static class Second extends AbstractSlot{

      @Override
      Object invoke(TargetMethod targetMethod) {

         Object result = null;
         System.out.println("增强逻辑");
         try {
            result= proceed(targetMethod);
         } catch (Exception e) {
            e.printStackTrace();
         }
         System.out.println("增强逻辑");
         return result;
      }
   }
}

2.基于拦截器的多重代理

2.1 拦截器

public interface MyInterceptor {

   Object invoke(MyInvocation myInvocation);
}
class One implements MyInterceptor{

   @Override
   public Object invoke(MyInvocation myInvocation) {

      Object result = null;
      System.out.println("1");
      result=myInvocation.proceed();
      System.out.println("4");
      return result;
   }
}
class Two implements MyInterceptor{

   @Override
   public Object invoke(MyInvocation myInvocation) {

      Object result = null;
      System.out.println("2");
      result=myInvocation.proceed();
      System.out.println("3");
      return result;
   }
}

2.2 增强器

public interface MyInvocation {

   Object proceed();
}
class MyInvocationImpl implements MyInvocation{

   List<MyInterceptor> interceptors = new ArrayList<>();

   int size =0;

   TargetMethod targetMethod;


   @Override
   public Object proceed() {

      try {
         return size == interceptors.size()?
               targetMethod.getMethod()
                     .invoke(
                           targetMethod.getTarget(),
                           targetMethod.getArgs()
                     ):
               interceptors.get(size++)
                     .invoke(this);
      } catch (IllegalAccessException | InvocationTargetException e) {
         e.printStackTrace();
      }
      return null;
   }

   public MyInvocationImpl(List<MyInterceptor> interceptors, TargetMethod targetMethod) {
      this.interceptors = interceptors;
      this.targetMethod = targetMethod;
   }
}

2.3 对方法的增强类

public class JdkProxy implements InvocationHandler {

   Object target;

   List<MyInterceptor> interceptors = new ArrayList<>();

   public void add(MyInterceptor a) {
      interceptors.add(a);
   }

   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      return new MyInvocationImpl(
            interceptors,
            new TargetMethod(
                  target,
                  method,
                  args
            )
      ).proceed();
   }

   public Object getProxy(){
      return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
      );
   }

   public JdkProxy(Object target) {
      this.target = target;
   }
}

2.4 测试类

public class Main {

   public static void main(String[] args) {

      JdkProxy jdkProxy = new JdkProxy(new Cat());
      jdkProxy.add(new One());
      jdkProxy.add(new Two());
      ((Animal) jdkProxy.getProxy()).eat("事务");
   }
}

三,AOP相关概念

AOP:全称是 Aspect Oriented Programming 即:面向切面编程。就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

  • 作用:
    在程序运行期间,不修改源码对已有方法进行增强。
  • 优势:
    减少重复代码
    提高开发效率
    维护方便

AOP 相关术语

  • Joinpoint(连接点):
    所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
  • Pointcut(切入点):
    所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
  • Advice(通知/增强):
    所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
    通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
  • Introduction(引介):
    引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。
  • Target(目标对象):被代理对象
    代理的目标对象。
  • Weaving(织入):
    是指把增强应用到目标对象来创建新的代理对象的过程。
    spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
  • Proxy(代理:
    一个类被 AOP 织入增强后,就产生一个结果代理类。
  • Aspect(切面):
    是切入点和通知(引介的结合)

Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

至此,我们通过两种方式完成了多重代理实现AOP,也简单介绍了两种实现动态代理的方式,和AOP相关的一些概念。下一篇将开始分析注解版Aop源码。