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 代理检测技巧
- 六、防坑指南:代理模式十诫
- 终极挑战:设计智能代理系统
快递柜的启示:为什么需要中间人?
📦 真实生活场景:
某小区快递乱象:
- 快递员随意堆放包裹(直接访问风险)
- 用户经常错过派送时间(响应不及时)
- 包裹安全性无法保障(缺乏访问控制)
物业引入智能快递柜后:
✅ 包裹安全存储
✅ 24小时自助领取
✅ 自动发送取件提醒
这就是代理模式的现实映射!让我们通过代码揭秘这个"中间商"如何优雅控制对象访问…
一、基础篇:三种代理方式初探
1.1 静态代理(传统中介模式)
// 数据库接口
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代理");}}}
}
六、防坑指南:代理模式十诫
- 循环代理警告:当代理对象相互注入时可能引发StackOverflow
- final方法陷阱:CGLIB无法代理final修饰的方法
- equals方法谜题:代理对象与原对象的equals可能不一致
- 异常处理黑洞:代理类要正确传递checked exception
- 性能关键路径:避免在高频调用方法上使用复杂代理
终极挑战:设计智能代理系统
架构设计题:
当需要支持:
- 动态切换代理策略
- 代理链式调用
- 代理流量统计分析
- 基于机器学习的自适应代理
如何设计:
- 可插拔的代理处理器
- 责任链模式的代理栈
- 代理监控数据埋点
- AI模型预测最佳代理方式