我的编程笔记记录我的编程笔记记录
首页
文章
分类
速记
相册
归档
RSS
首页
文章
分类
速记
相册
归档
RSS
  • 全部文章
  • 开发 (25)

    • 编程语言 (9)

      • css (1)

        • 【布局】css布局一本通【转载】
      • javascript (2)

        • canvas (2)

          • canvas处理视频
          • canvas 通过图像数据点阵重新绘制图像
      • php (3)

        • 调试 (1)

          • Xdebug的工作原理及在phpstorm下的配置
        • 源码 (1)

          • PHP实现ZIP流式打包下载(Zip on the fly)
        • composer常用指令
      • vuejs (3)

        • 2.x (1)

          • 封装一个三方组件的通用套路
        • vue中使用jsx开发组件
        • vite小技巧
    • 基础 (1)

      • patterns (1)

        • 结构型 (1)

          • 代理
    • 量化 (1)

      • qmt (1)

        • 大QMT关闭文件IO和Socket后,如何从外部获取特色数据和信号?如何得心应手的使用QMT呢?
    • 数据库 (4)

      • mongodb (1)

        • MongoDB快速入门
      • mysql (3)

        • 基础知识 (2)

          • mysql分页的两种方式
          • mysql取随机数字
        • sql性能监控工具
    • linux (1)

      • 常用 (1)

        • wget下载整个网站或者特定目录
    • tools (9)

      • 开发环境 (2)

        • vscode中的代码片段
        • linux下搭建samba用来和windows共享文件
      • 运维 (1)

        • 安装minio做图床
      • ide (2)

        • IDEA必装插件
        • IDEA文件模板变量
      • DOS常用指令
      • nginx 之 proxy_pass详解
      • nginx下websocket反向代理
      • github快速找项目

代理

什么是代理模式

代理模式是一种结构型设计模式,其设计思想就和其名字一样,就是给某个对象提供一个代理对象,由代理对象来控制对原对象的访问。

(原文此处有一张代理模式的 UML 结构图,原图床已失效,未恢复)

代理模式的使用场景有哪些

代理模式的使用场景有很多,比如:

  1. 在访问某个对象时需要添加额外的逻辑,比如权限控制、日志记录等。
  2. 在访问某个对象时需要对原对象进行优化,比如缓存、延迟加载等。
  3. 在访问某个对象时需要对原对象进行保护,比如只有特定的人才能访问等。
  4. 在访问某个对象时需要对原对象进行扩展,比如增加统计信息等。

代理模式的优缺点

代理模式最大的优点就是,代理模式能够对原对象进行扩展,而不需要修改原对象的代码。

代理模式最大的缺点就是,由于代理模式增加了代理对象,所以会增加系统的复杂度。

代理模式的实现(Java)

代理模式的实现有很多种,比如静态代理、动态代理、CGLIB代理。这里分别用这三种方式实现给一个请求添加日志记录的功能。

原始类

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject request");
    }
}

静态代理

public class ProxySubject implements Subject {
    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        System.out.println("ProxySubject request start");
        subject.request();
        System.out.println("ProxySubject request end");
    }
}

动态代理

Java 提供的动态代理是通过反射实现的,其原理是通过Proxy.newProxyInstance方法创建一个代理对象,然后通过代理对象调用被代理对象的方法,最后在代理对象的方法中添加额外的逻辑。这种方式的缺点是,被代理的类必须实现接口。如果没有实现接口,可以使用CGLIB代理。

public class DynamicProxySubject implements InvocationHandler {
    private Subject subject;

    public DynamicProxySubject(Subject subject) {
        this.subject = subject;
    }

    // 实现InvocationHandler接口的invoke方法后JVM会自动调用该方法并传入参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxySubject request start");
        Object result = method.invoke(subject, args);
        System.out.println("DynamicProxySubject request end");
        return result;
    }
}

// 使用动态代理
Subject subject = new RealSubject();
Subject proxySubject = (Subject) Proxy.newProxyInstance(
        subject.getClass().getClassLoader(),
        subject.getClass().getInterfaces(),
        new DynamicProxySubject(subject));
proxySubject.request();

CGLIB代理

CGLIB代理是通过继承的方式实现的,所以被代理的类不能是final类,而且被代理的方法不能是final方法。 其原理是通过JDK的Instrumentation API在运行时动态修改字节码,实现对类的继承,然后通过继承的方式实现代理。如果被代理的类没有实现接口,那么CGLIB会自动创建一个接口并实现该接口,然后再通过继承的方式实现代理。

public class CglibProxySubject implements MethodInterceptor {
    private Subject subject;

    public CglibProxySubject(Subject subject) {
        this.subject = subject;
    }

    // 实现MethodInterceptor接口的intercept方法后CGLIB会自动调用该方法并传入参数
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CglibProxySubject request start");
        Object result = method.invoke(subject, objects);
        System.out.println("CglibProxySubject request end");
        return result;
    }
}

// 使用CGLIB代理
Subject subject = new RealSubject();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(subject.getClass());
enhancer.setCallback(new CglibProxySubject(subject));
Subject proxySubject = (Subject) enhancer.create();
proxySubject.request();
最后更新: 2026/10/5 16:34
← 上一篇sql性能监控工具下一篇 →安装minio做图床

最新文章

  • 用「速记」把维护成本降下来
  • 大QMT关闭文件IO和Socket后,如何从外部获取特色数据和信号?如何得心应手的使用QMT呢?开发 / 量化 / qmt
  • MongoDB快速入门开发 / 数据库 / mongodb