• 把Java代理说清楚


    简介

    • 什么是代理?

      通过第三方(代理)来访问目标对象

      例如

      1. 买房,通过房产中介买房而不是直接找开发商

      2. 看电影,去电影院而不是直接购买电影版权

    • 为什么需要代理?

      协调调用者和被调用者,降低耦合性

      例如

      1. 买房,客户不需要调查所有的房产信息,而是根据中介整理的信息进行选择
      2. 看电影,消费者不需要关系版权期限等,而是直接购买电影票看电影
    • 代理有什么用?

      能够在不影响目标对象的基础上,增强功能

      例如

      1. 中介帮助客户找到最适合的房产,而客户支付一定的费用

      2. 影院提供大量电影供消费者选择,消费者支付一定的费用

        (否则看一部电影,买一次版权,代价巨大)

    静态代理

    饭店可以提供食物,而用户购买食物
    如果用户不方便出门,那样饭店赚不到钱,客户吃不到东西
    但是通过外卖平台,就可以在不影响饭店做菜的基础上,为客户提供食物

    • 外卖平台本身不提供食物

    • 整个过程分为3步

      1. 客户点餐(平台提供的点餐系统)
      2. 饭店做菜
      3. 平台配送
        接下开用代码模拟一下这个过程
    • 饭店

      public interface Restaurant {
          /**
           * 提供食物
           * @param name 食物名称
           */
          public void food(String name);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 为什么用接口?
        因为有各种饭店,但他们都能够提供食物
    • 肯德基

      public class KFC implements Restaurant{
          @Override
          public void food(String name) {
              System.out.println(name + " ( KFC )");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 外卖平台

      public class Takeout implements Restaurant {
          // 入驻平台的饭店 (理论上有多个,应该是数组,但这里做简化)
          Restaurant restaurant;
      
          Takeout(Restaurant restaurant) {
              this.restaurant = restaurant;
          }
          
          // 提供食物
          @Override
          public void food(String name) {
          	// 客户点餐
              order(name);
              
      		// 让饭店做饭
              this.restaurant.food(name);
      
      		// 配送
              deliver();
          }
      
          // 点餐
          public void order(String name) {
              System.out.println("点餐 : " + name);
          }
      
          // 配送
          public void deliver() {
              System.out.println("送餐");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
    • 测试

      public class App {
          public static void main(String[] args) {
              // KFC 开店
              Restaurant kfc = new KFC();
      
              // KFC 入驻 外卖平台
              Takeout takeout = new Takeout(kfc);
      
              // 客户在外卖平台点餐
              takeout.food("汉堡");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      控制台输出

      点餐 : 汉堡
      汉堡 ( KFC )
      送餐
      
      • 1
      • 2
      • 3
    • 为什么叫静态呢?
      代理对象(外卖平台)必须事先存在

    动态代理

    • 代理对象不需要实现存在,而是在代码运行的过程中生成

    • 需要借助java.lang.reflect.ProxynewProxyInstance方法

      // 获取代理对象的实例
      public static Object newProxyInstance(
          ClassLoader loader,  // 类加载器
          Class<?>[] interfaces,  // 接口列表
          InvocationHandler h  // 处理程序
      )
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 类加载器:用于生成类实例
      • 接口列表:目标对象所实现的功能(例如餐厅能够做饭,但还有可能提供其他服务)
      • 处理程序:对目标对象增强的功能(例如外卖平台的手机点餐、配送)
    • 比较陌生的是处理程序(java.lang.reflect.InvocationHandler

      public interface InvocationHandler {
          public Object invoke(
      	    Object proxy,  // 调用方法的代理对象
      	    Method method,   // 调用的方法
      	    Object[] args  // 调用方法的参数
          ) throws Throwable;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 定义处理程序

      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      
      public class Takeout implements InvocationHandler {
          private Object obj;
      
          Takeout(Object obj) {
              this.obj = obj;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              // 点餐
              order(args);
      
              // 做饭
              Object result = method.invoke(obj, args);
      
              // 送餐
              deliver();
      
              // 虽然 food 方法没有返回值,但为了适应所有的情况
              return result;
          }
      
          // 点餐
          public void order(Object[] args) {
              System.out.print("点餐 : ");
              for (Object arg : args) {
                  System.out.println(arg);
              }
          }
      
          // 送餐
          public void deliver() {
              System.out.println("送餐");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
    • 定义代理对象获取类
      通过该类的静态方法来获取代理对象

      import java.lang.reflect.Proxy;
      
      public class TakeoutProxy {
      
          // 为饭店生成一个代理
          public static Restaurant getRestaurant(Object obj) {
              return (Restaurant) Proxy.newProxyInstance(
                      obj.getClass().getClassLoader(),
                      obj.getClass().getInterfaces(),
                      new Takeout(obj)
              );
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 测试程序
      public class App {
          public static void main(String[] args) {
              // KFC 开店
              Restaurant kfc = new KFC();
      
              // // KFC 入驻 外卖平台
              Restaurant takeout = TakeoutProxy.getRestaurant(kfc);
      
              // 客户在外卖平台点餐
              takeout.food("汉堡");
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      控制台输出

      点餐 : 汉堡
      汉堡 ( KFC )
      送餐
      
      • 1
      • 2
      • 3

    区别

    • 静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类

      • 点餐和送餐本质上是,下订单与配送,所以动态代理不仅仅能够处理饭店,还能够处理花店、超市、等等业务。

      • 乍一看好像两种方法没啥区别,但是静态代理中,把目标对象固定了(只能是Restaurant

        // 让饭店做饭
        this.restaurant.food(name);
        
        • 1
        • 2
  • 相关阅读:
    【Python】PySpark 数据处理 ② ( 安装 PySpark | PySpark 数据处理步骤 | 构建 PySpark 执行环境入口对象 )
    Seata四大模式之XA模式详解及代码实现
    阿里云服务器u1和经济型e系列性能差异?哪个比较好?
    SpringMVC之JSR303和拦截器
    来看看Python MetaClass元类详解
    一站式元数据治理平台——Datahub
    springboot相关-JDBC
    5_1 计算机网络
    软件过程与建模学习之:Ethics, ACs Code Ethics, IEEE Code of Ethics
    OWASP发布十大开源软件安全风险清单
  • 原文地址:https://blog.csdn.net/m0_52733659/article/details/126295856