Java 代理模式详解

如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

  1. 代理模式的定义
    • 代理模式是一种设计模式,它为其他对象提供一种代理,以控制对这个对象的访问。代理对象可以在客户端和目标对象之间起到中介的作用,它可以在不改变目标对象接口的情况下,增强目标对象的功能或者对目标对象的访问进行控制。
  1. 代理模式的结构
    • 主题(Subject)接口 :定义了真实对象和代理对象共同的接口,客户端通过这个接口来访问真实对象和代理对象。例如,在一个文件读取系统中,主题接口可以是FileReaderSubject,它定义了读取文件内容的抽象方法,如readFile(String fileName)
    • 真实主题(Real Subject) :实现了主题接口,是真正完成业务逻辑的对象。比如,在文件读取系统中,真实主题可以是FileReaderImpl,它实现了FileReaderSubject接口,具体实现了从文件系统中读取文件内容的方法。
    • 代理(Proxy) :同样实现了主题接口,代理对象内部包含了真实主题对象的引用。它可以在调用真实主题对象的方法之前或之后,添加额外的逻辑,如权限验证、日志记录等。在文件读取系统中,代理对象FileReaderProxy可以在调用FileReaderImplreadFile方法之前,先检查用户是否有读取文件的权限。
  1. 代理模式的类型
    • 静态代理

      // 接口定义
      interface Calculator {
      int add(int a, int b);
      }
      // 真实主题(被代理类)
      class CalculatorImpl implements Calculator {
      @Override
      public int add(int a, int b) {
      return a + b;
      }
      }
      // 代理类
      class CalculatorProxy implements Calculator {
      private Calculator calculator;
      public CalculatorProxy(Calculator calculator) {
      this.calculator = calculator;
      }
      @Override
      public int add(int a, int b) {
      System.out.println("在加法运算前进行日志记录");
      int result = calculator.add(a, b);
      System.out.println("在加法运算后进行日志记录");
      return result;
      }
      }

      • 定义:静态代理是在编译时期就已经确定了代理类和被代理类的关系。代理类和被代理类都需要实现同一个接口,代理类通过持有被代理类的实例来调用其方法,并在调用前后添加自己的逻辑。
      • 示例 :假设我们有一个接口Calculator,它有一个方法add(int a, int b)用于计算两数之和。
      • 在这个例子中,CalculatorProxyCalculatorImpl的代理类。当客户端调用CalculatorProxyadd方法时,它会先打印日志,然后调用CalculatorImpladd方法,最后再打印日志。
    • 动态代理

      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      // 动态代理的调用处理器
      class CalculatorInvocationHandler implements InvocationHandler {
      private Object target;
      public CalculatorInvocationHandler(Object target) {
      this.target = target;
      }
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("在动态代理方法调用前进行日志记录");
      Object result = method.invoke(target, args);
      System.out.println("在动态代理方法调用后进行日志记录");
      return result;
      }
      }

      Calculator calculator = new CalculatorImpl();
      Calculator proxy = (Calculator) Proxy.newProxyInstance(
      Calculator.class.getClassLoader(),
      new Class[]{Calculator.class},
      new CalculatorInvocationHandler(calculator));
      int result = proxy.add(1, 2);

      • 定义 :动态代理是在运行时动态地生成代理类。在Java中,主要通过java.lang.reflect.Proxy类和InvocationHandler接口来实现动态代理。动态代理不需要像静态代理那样为每个被代理类都编写一个代理类,它可以根据需要动态地创建代理对象。
      • 示例 :还是以上面的Calculator接口为例,我们可以这样实现动态代理:
      • 客户端使用动态代理的代码如下:
      • 在这个动态代理的例子中,CalculatorInvocationHandler是实现了InvocationHandler接口的调用处理器。Proxy.newProxyInstance方法会在运行时动态地生成一个代理对象,这个代理对象实现了Calculator接口。当客户端调用代理对象的方法时,会触发InvocationHandlerinvoke方法,在这个方法中可以添加代理逻辑,如日志记录,然后再调用真实对象(CalculatorImpl)的方法。
  1. 代理模式的应用场景
    • 远程代理:用于访问远程对象,就好像访问本地对象一样。例如,在分布式系统中,客户端通过代理对象来调用远程服务器上的对象。代理对象负责处理网络通信等细节,如Java RMI(Remote Method Invocation)就使用了远程代理。
    • 虚拟代理:当创建一个对象的代价比较大(如加载大型资源文件、初始化复杂对象等)时,可以使用虚拟代理。虚拟代理先创建一个简单的代理对象来代替真实对象,当真正需要使用真实对象时,再进行创建。例如,在网页加载图片时,可以先显示一个占位符(代理),当图片真正加载完成后(真实对象创建完成),再显示真实的图片。
    • 安全代理:用于控制对敏感对象的访问。代理对象可以在访问真实对象之前,对用户的权限进行验证。例如,在企业级应用中,对某些敏感数据的访问,只有具有特定权限的用户才能通过代理访问到真实的数据。
相关推荐
尘觉1 天前
创作 1024 天|把热爱写成长期主义
数据库·1024程序员节
写点什么呢2 天前
Word使用记录
word·1024程序员节
开开心心就好2 天前
内存清理工具点击清理,自动间隔自启
linux·运维·服务器·安全·硬件架构·材料工程·1024程序员节
开开心心就好3 天前
内存清理工具开源免费,自动优化清理项
linux·运维·服务器·python·django·pdf·1024程序员节
张萌杰6 天前
深度学习的基础知识(常见名词解释)
人工智能·深度学习·机器学习·1024程序员节
开开心心就好7 天前
免费无广告卸载工具,轻便安全适配全用户
linux·运维·服务器·网络·安全·启发式算法·1024程序员节
开开心心就好8 天前
图片格式转换工具,右键菜单一键转换简化
linux·运维·服务器·python·django·pdf·1024程序员节
徐子童10 天前
网络协议---TCP协议
网络·网络协议·tcp/ip·面试题·1024程序员节
扫地的小何尚12 天前
NVIDIA RTX PC开源AI工具升级:加速LLM和扩散模型的性能革命
人工智能·python·算法·开源·nvidia·1024程序员节
数据皮皮侠AI13 天前
上市公司股票名称相似度(1990-2025)
大数据·人工智能·笔记·区块链·能源·1024程序员节