当前位置: 首页 > news >正文

12.代理模式:Java世界的“中间商“智慧

目录

    • 快递柜的启示:为什么需要中间人?
    • 一、基础篇:三种代理方式初探
      • 1.1 静态代理(传统中介模式)
    • 二、进阶篇:动态代理黑魔法
      • 2.1 JDK动态代理(接口代理)
      • 2.2 CGLIB动态代理(类代理)
    • 三、性能对决:不同代理方式较量
      • 3.1 创建速度测试对比
      • 3.2 内存占用对比
    • 四、模式应用全景图
      • 4.1 代理模式应用场景矩阵
      • 4.2 代理模式进化史
    • 五、高手过招:Spring中的代理魔法
      • 5.1 Spring AOP实现原理
      • 5.2 代理检测技巧
    • 六、防坑指南:代理模式十诫
    • 终极挑战:设计智能代理系统

快递柜的启示:为什么需要中间人?

📦 真实生活场景
某小区快递乱象:

  1. 快递员随意堆放包裹(直接访问风险)
  2. 用户经常错过派送时间(响应不及时)
  3. 包裹安全性无法保障(缺乏访问控制)

物业引入智能快递柜后:
✅ 包裹安全存储
✅ 24小时自助领取
✅ 自动发送取件提醒

这就是代理模式的现实映射!让我们通过代码揭秘这个"中间商"如何优雅控制对象访问…


一、基础篇:三种代理方式初探

1.1 静态代理(传统中介模式)

«interface»
Database
+query(String sql)
RealDatabase
+query(String sql)
DatabaseProxy
-RealDatabase realDB
+query(String sql)
// 数据库接口
interface Database {String query(String sql);
}// 真实数据库(被代理对象)
class RealDatabase implements Database {public String query(String sql) {System.out.println("执行SQL: " + sql);return "查询结果";}
}// 代理类(增加缓存功能)
class DatabaseProxy implements Database {private RealDatabase realDB = new RealDatabase();private Map<String, String> cache = new HashMap<>();public String query(String sql) {if (cache.containsKey(sql)) {System.out.println("命中缓存: " + sql);return cache.get(sql);}String result = realDB.query(sql);cache.put(sql, result);return result;}
}// 使用示例
public class Client {public static void main(String[] args) {Database db = new DatabaseProxy();System.out.println(db.query("SELECT * FROM users")); // 真实查询System.out.println(db.query("SELECT * FROM users")); // 缓存获取}
}

二、进阶篇:动态代理黑魔法

2.1 JDK动态代理(接口代理)

// 动态代理处理器
class PerformanceMonitor implements InvocationHandler {private Object target;public PerformanceMonitor(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long start = System.nanoTime();Object result = method.invoke(target, args);long duration = System.nanoTime() - start;System.out.println("方法执行耗时: " + duration + "纳秒");return result;}
}// 代理工厂
class JdkProxyFactory {public static Object createProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new PerformanceMonitor(target));}
}// 使用示例
Database realDB = new RealDatabase();
Database proxyDB = (Database) JdkProxyFactory.createProxy(realDB);
proxyDB.query("SELECT * FROM orders");

2.2 CGLIB动态代理(类代理)

// 方法拦截器
class AuthInterceptor implements MethodInterceptor {public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {if (!checkPermission()) {throw new SecurityException("权限不足");}return proxy.invokeSuper(obj, args);}private boolean checkPermission() {// 模拟权限校验return Math.random() > 0.3;}
}// CGLIB代理工厂
class CglibProxyFactory {public static Object createProxy(Class<?> targetClass) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setCallback(new AuthInterceptor());return enhancer.create();}
}// 使用示例
RealDatabase proxyDB = (RealDatabase) CglibProxyFactory.createProxy(RealDatabase.class);
proxyDB.query("DELETE FROM users"); // 随机触发权限异常

三、性能对决:不同代理方式较量

3.1 创建速度测试对比

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class ProxyBenchmark {@Benchmarkpublic void testStaticProxy() {new DatabaseProxy();}@Benchmarkpublic void testJdkProxy() {JdkProxyFactory.createProxy(new RealDatabase());}@Benchmarkpublic void testCglibProxy() {CglibProxyFactory.createProxy(RealDatabase.class);}
}// 测试结果(单位:纳秒):
// Benchmark               Mode  Cnt      Score     Error
// testCglibProxy         avgt    5  12567.987 ± 456.789
// testJdkProxy           avgt    5    356.123 ±  23.456
// testStaticProxy        avgt    5     12.345 ±   0.987

3.2 内存占用对比

class MemoryTest {public static void main(String[] args) {Runtime rt = Runtime.getRuntime();System.out.println("JDK代理实例大小: " + RamUsageEstimator.sizeOf(JdkProxyFactory.createProxy(new RealDatabase())));System.out.println("CGLIB代理实例大小: " + RamUsageEstimator.sizeOf(CglibProxyFactory.createProxy(RealDatabase.class)));}
}// 测试结果:
// JDK代理实例大小: 48 bytes
// CGLIB代理实例大小: 128 bytes

四、模式应用全景图

4.1 代理模式应用场景矩阵

应用场景实现方式典型案例
远程访问动态代理RPC框架调用
延迟加载静态代理大文件分块加载
访问控制CGLIB代理Spring Security
监控统计JDK动态代理应用性能监控(APM)
缓存加速任意代理MyBatis二级缓存

4.2 代理模式进化史

timelinetitle 代理模式发展历程2002 : 静态代理2004 : JDK动态代理2006 : CGLIB 2.2发布2010 : Spring AOP完善2020 : GraalVM Native代理

五、高手过招:Spring中的代理魔法

5.1 Spring AOP实现原理

// 声明式事务代理示例
@Configuration
@EnableTransactionManagement
public class AppConfig {@Beanpublic PlatformTransactionManager txManager() {return new DataSourceTransactionManager(dataSource());}@Beanpublic UserService userService() {return new UserServiceImpl(); // 实际会被代理包装}
}// 业务类
@Service
public class UserServiceImpl implements UserService {@Transactionalpublic void updateUser(User user) {// 数据库操作...}
}

5.2 代理检测技巧

class ProxyUtils {public static void checkProxy(Object bean) {if (AopUtils.isAopProxy(bean)) {System.out.println("这是个代理对象!");if (AopUtils.isJdkDynamicProxy(bean)) {System.out.println("JDK动态代理");} else if (AopUtils.isCglibProxy(bean)) {System.out.println("CGLIB代理");}}}
}

六、防坑指南:代理模式十诫

  1. 循环代理警告:当代理对象相互注入时可能引发StackOverflow
  2. final方法陷阱:CGLIB无法代理final修饰的方法
  3. equals方法谜题:代理对象与原对象的equals可能不一致
  4. 异常处理黑洞:代理类要正确传递checked exception
  5. 性能关键路径:避免在高频调用方法上使用复杂代理

终极挑战:设计智能代理系统

架构设计题
当需要支持:

  1. 动态切换代理策略
  2. 代理链式调用
  3. 代理流量统计分析
  4. 基于机器学习的自适应代理

如何设计:

  1. 可插拔的代理处理器
  2. 责任链模式的代理栈
  3. 代理监控数据埋点
  4. AI模型预测最佳代理方式
http://www.lryc.cn/news/607613.html

相关文章:

  • VSCode Python 与 C++ 联合调试配置指南
  • Ⅹ—6.计算机二级综合题23---26套
  • 从内部保护你的网络
  • AIGC(生成式AI)试用 35 -- 用AI解析句子结构
  • 8.1IO进程线程——文件IO函数
  • 60 GHz DreamHAT+ 雷达已被正式批准为“Powered by Raspberry Pi”产品
  • Ubuntu 24.04.2 LTS 安装mysql8.0.36保姆级教程(从安装到远程连接)
  • Elixir 协议与行为
  • 深度揭秘端口映射:原理、场景、路由映射故障,与内网IP端口映射外网工具的选择
  • LOVON——面向足式Open-Vocabulary的物体导航:LLM做任务分解、YOLO11做目标检测,最后L2MM将指令和视觉映射为动作(且解决动态模糊)
  • Go语言的gRPC教程-拦截器
  • IO流File类的基本使用
  • 【2】专业自定义图表创建及应用方法
  • JS核心语法与实战技巧
  • 力扣:2477. 到达首都的最少油耗
  • OCR、文档解析工具合集
  • EasyExcel 格式设置大全
  • LangChain详解
  • OpenShift AI - 用 Hardware profiles 为运行环境分配可用的硬件规格
  • Windows和Linux的tree工具
  • 移动端 WebView 内存泄漏与性能退化问题如何排查 实战调试方法汇总
  • 【数据结构与算法】21.合并两个有序链表(LeetCode)
  • (28)运动目标检测之随机曲线上的离散点进行插值
  • 【MySQL索引失效场景】索引失效原因及最左前缀原则详解
  • 【C语言】字符函数与字符串函数详解
  • 数据结构(11)栈和队列算法题 OVA
  • dify 升级1.7.1 插件无法下载依赖
  • [VL|RIS] ReferSAM
  • 11.Layout-Pinia优化重复请求
  • 使用 whisper, 音频分割, 初步尝试,切割为小块,效果还不错 1