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)就使用了远程代理。
    • 虚拟代理:当创建一个对象的代价比较大(如加载大型资源文件、初始化复杂对象等)时,可以使用虚拟代理。虚拟代理先创建一个简单的代理对象来代替真实对象,当真正需要使用真实对象时,再进行创建。例如,在网页加载图片时,可以先显示一个占位符(代理),当图片真正加载完成后(真实对象创建完成),再显示真实的图片。
    • 安全代理:用于控制对敏感对象的访问。代理对象可以在访问真实对象之前,对用户的权限进行验证。例如,在企业级应用中,对某些敏感数据的访问,只有具有特定权限的用户才能通过代理访问到真实的数据。
相关推荐
学传打活5 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng16813 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心15 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552721 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552721 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝23 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552723 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552724 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u0103055271 个月前
Java实用类应用精讲
人工智能·1024程序员节
u0103055271 个月前
Java I/O核心操作实战
人工智能·1024程序员节