
静态代理模式详解一、什么是静态代理静态代理是代理模式最基础的实现方式。它的核心是手动编写一个代理类实现与目标类相同的接口在代理类中持有目标对象的引用方法调用时在目标方法前后插入增强逻辑。“静态”的含义是代理类在编译期就已经确定不是运行时动态生成的。你需要手写这个类编译后就是一个普通的.class文件。二、结构静态代理包含三个角色角色说明示例抽象主题定义公共接口UserService真实主题实现接口执行业务逻辑UserServiceImpl代理实现同一接口持有真实主题引用增强逻辑UserServiceProxy客户端面向接口编程不关心背后是真实对象还是代理对象。三、完整代码示例1. 抽象主题publicinterfaceUserService{voidsave(Useruser);UserfindById(Longid);}2. 真实主题publicclassUserServiceImplimplementsUserService{Overridepublicvoidsave(Useruser){System.out.println(保存用户user.getName());}OverridepublicUserfindById(Longid){System.out.println(查询用户id);returnnewUser(id,张三);}}3. 代理类publicclassUserServiceProxyimplementsUserService{// 持有真实对象的引用privatefinalUserServicetarget;publicUserServiceProxy(UserServicetarget){this.targettarget;}Overridepublicvoidsave(Useruser){// 前置增强System.out.println(【日志】开始保存用户);longstartSystem.currentTimeMillis();// 调用真实对象的方法target.save(user);// 后置增强longcostSystem.currentTimeMillis()-start;System.out.println(【日志】保存完成耗时costms);}OverridepublicUserfindById(Longid){System.out.println(【日志】开始查询用户);Userusertarget.findById(id);System.out.println(【日志】查询完成);returnuser;}}4. 客户端publicclassClient{publicstaticvoidmain(String[]args){// 创建真实对象UserServicetargetnewUserServiceImpl();// 创建代理对象注入真实对象UserServiceproxynewUserServiceProxy(target);// 通过代理调用proxy.save(newUser(1L,张三));proxy.findById(1L);}}输出【日志】开始保存用户 保存用户张三 【日志】保存完成耗时0ms 【日志】开始查询用户 查询用户1 【日志】查询完成四、静态代理能做什么代理类在调用真实方法前后插入逻辑常见的增强场景增强类型示例日志记录记录方法名、参数、返回值性能监控统计方法执行耗时事务控制方法前开启事务方法后提交/回滚权限校验方法前检查用户权限缓存方法前查缓存命中则直接返回参数校验方法前校验参数合法性五、静态代理的缺点1. 类数量翻倍每个目标类都需要一个对应的代理类。项目中有 100 个 Service就要写 100 个 Proxy。UserService → UserServiceProxy OrderService → OrderServiceProxy ProductService → ProductServiceProxy ...2. 接口变化时维护成本高接口新增一个方法真实类和代理类都要修改。如果漏改了代理类编译不通过。publicinterfaceUserService{voidsave(Useruser);UserfindById(Longid);voiddeleteById(Longid);// 新增方法}UserServiceImpl和UserServiceProxy都必须实现deleteById。3. 重复代码多个代理类的增强逻辑相似无法复用。每个代理类都要写一遍日志、事务、权限的代码。4. 编译期确定代理关系在编译期就固定了无法运行时动态切换。如果需要一个目标对象对应多个代理日志代理、事务代理、权限代理需要写多个代理类并手动组合。六、静态代理 vs 动态代理对比维度静态代理动态代理代理类生成时机编译期手动编写运行时动态生成类数量每个目标类一个代理无需手动编写代理类接口变化需修改代理类自动适配代码复用差增强逻辑重复好统一在 InvocationHandler灵活性低高性能略高无反射略低反射调用适用场景目标类少、增强逻辑简单目标类多、增强逻辑统一七、静态代理在 Spring 中的影子Spring AOP 默认使用动态代理但静态代理的思想在 Spring 中仍有体现TransactionTemplate手动控制事务相当于把事务逻辑封装在模板中业务代码通过回调执行。transactionTemplate.execute(status-{userDao.save(user);returnnull;});JdbcTemplate把连接管理、异常处理、资源释放等逻辑封装在模板中业务代码只关注 SQL 和结果映射。AOP 的 XML 配置在 XML 中配置代理工厂本质上也是代理思想。八、适用场景静态代理适合以下场景目标类数量少1-3 个且不会频繁变化增强逻辑简单不需要统一管理需要精确控制每个方法的增强行为对性能有极致要求不想引入反射开销如果目标类多、增强逻辑统一应该用动态代理。九、一个完整的静态代理示例// 抽象主题publicinterfaceCalculator{intadd(inta,intb);intdivide(inta,intb);}// 真实主题publicclassCalculatorImplimplementsCalculator{Overridepublicintadd(inta,intb){returnab;}Overridepublicintdivide(inta,intb){returna/b;}}// 代理增加日志和异常处理publicclassCalculatorProxyimplementsCalculator{privatefinalCalculatortarget;publicCalculatorProxy(Calculatortarget){this.targettarget;}Overridepublicintadd(inta,intb){System.out.println(调用 add(a, b));intresulttarget.add(a,b);System.out.println(结果result);returnresult;}Overridepublicintdivide(inta,intb){System.out.println(调用 divide(a, b));try{intresulttarget.divide(a,b);System.out.println(结果result);returnresult;}catch(ArithmeticExceptione){System.out.println(除数不能为 0);throwe;}}}// 客户端publicclassClient{publicstaticvoidmain(String[]args){CalculatortargetnewCalculatorImpl();CalculatorproxynewCalculatorProxy(target);proxy.add(1,2);// 调用 add(1, 2) → 结果3proxy.divide(10,2);// 调用 divide(10, 2) → 结果5proxy.divide(10,0);// 调用 divide(10, 0) → 除数不能为 0}}十、总结维度核心要点本质手动编写代理类实现与目标类相同的接口角色抽象主题、真实主题、代理增强方式在调用目标方法前后插入逻辑优点实现简单、无反射开销、精确控制缺点类数量翻倍、接口变化维护成本高、增强逻辑重复适用场景目标类少、增强逻辑简单、不需要统一管理与动态代理对比静态代理编译期确定动态代理运行时生成静态代理是理解代理模式的起点。它简单直接但扩展性差。理解静态代理的局限性就能理解为什么 Spring AOP 选择动态代理——动态代理解决了静态代理“类数量爆炸”和“接口变化维护成本高”这两个核心问题。