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 天前
Jmeter中的断言(二)
测试工具·jmeter·1024程序员节
西电研梦1 天前
考研倒计时30天丨和西电一起向前!再向前!
人工智能·考研·1024程序员节·西电·西安电子科技大学
惜.己2 天前
Jmeter中的断言(四)
测试工具·jmeter·1024程序员节
·云扬·2 天前
Java IO 与 BIO、NIO、AIO 详解
java·开发语言·笔记·学习·nio·1024程序员节
网安_秋刀鱼2 天前
PHP代码审计 --MVC模型开发框架&rce示例
开发语言·web安全·网络安全·php·mvc·1024程序员节
HUODUNYUN2 天前
小程序免备案:快速部署与优化的全攻略
服务器·网络·web安全·小程序·1024程序员节
惜.己3 天前
Jmeter的后置处理器(二)
测试工具·github·1024程序员节
惜.己3 天前
Jmeter中的断言(一)
测试工具·jmeter·1024程序员节
cainiao0806053 天前
《物理学进展》
1024程序员节·核心期刊·知网期刊·职称评审
FFDUST3 天前
C++ —— string类(上)
c语言·开发语言·数据结构·c++·stl·1024程序员节