
1. 代理模式基础概念解析代理模式是面向对象编程中一种常见的设计模式它为其他对象提供一种代理以控制对这个对象的访问。在实际开发中我们经常会遇到需要控制对象访问的场景比如远程对象访问RPC调用创建开销大的对象延迟加载需要安全控制的对象需要额外功能的对象日志、监控等代理模式的核心在于通过一个代理对象来间接访问目标对象这样可以在不修改原始对象的基础上增加额外的功能或控制逻辑。根据代理类的创建时机和方式我们可以将代理分为静态代理和动态代理两大类。提示代理模式与装饰器模式在实现上有些相似但它们的关注点不同。装饰器模式侧重于动态添加功能而代理模式侧重于控制访问。2. 静态代理详解与实现2.1 静态代理的实现原理静态代理是最基础的代理实现方式它的特点是在编译期就已经确定了代理关系。具体实现需要定义业务接口创建真实对象实现业务接口创建代理类同样实现业务接口在代理类中持有真实对象的引用在代理类方法中调用真实对象方法并添加额外逻辑// 业务接口 public interface UserService { void saveUser(String user); } // 真实对象 public class UserServiceImpl implements UserService { Override public void saveUser(String user) { System.out.println(保存用户 user); } } // 代理类 public class UserServiceProxy implements UserService { private UserService target; public UserServiceProxy(UserService target) { this.target target; } Override public void saveUser(String user) { System.out.println(开始事务...); target.saveUser(user); System.out.println(提交事务...); } }2.2 静态代理的优缺点分析优点实现简单易于理解编译期就能确定代理关系运行效率高可以在不修改目标对象的前提下扩展功能缺点每个真实对象都需要创建一个代理类当接口变化时真实对象和代理类都需要修改如果系统中有大量需要代理的类会导致代理类数量膨胀代理类和真实对象的关系在编译期就已经确定不够灵活2.3 静态代理的适用场景静态代理适合以下场景代理类数量较少且稳定的系统需要高性能的场景因为静态代理没有运行时开销需要对少量特定方法进行增强的场景注意在实际项目中如果发现需要为大量类创建几乎相同的代理逻辑时就应该考虑使用动态代理了。3. 动态代理深入解析3.1 动态代理的核心机制动态代理与静态代理最大的区别在于代理类的创建时机。动态代理的代理类是在程序运行时动态生成的主要分为两类实现方式基于接口的动态代理JDK原生支持使用java.lang.reflect.Proxy类基于类的动态代理第三方库如CGLib实现动态代理的核心在于不需要手动编写代理类通过反射机制在运行时生成代理类通过InvocationHandler接口统一处理代理逻辑// 动态代理示例 public class DynamicProxyHandler implements InvocationHandler { private Object target; public DynamicProxyHandler(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; } } // 使用动态代理 UserService userService new UserServiceImpl(); UserService proxy (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new DynamicProxyHandler(userService) ); proxy.saveUser(张三);3.2 JDK动态代理实现细节JDK动态代理的实现依赖于以下几个核心类java.lang.reflect.Proxy负责创建代理对象java.lang.reflect.InvocationHandler代理逻辑处理器实现步骤创建实现InvocationHandler接口的处理器类通过Proxy.newProxyInstance()方法创建代理对象代理对象调用方法时会自动转发到InvocationHandler.invoke()方法重要限制只能代理接口不能代理类目标对象必须实现至少一个接口性能相比静态代理稍差因为涉及反射调用3.3 CGLib动态代理实现当目标对象没有实现接口时可以使用CGLib实现基于类的动态代理。CGLib通过继承目标类并在子类中重写方法来实现代理。// CGLib代理示例 public class CglibProxy implements MethodInterceptor { private Object target; public Object getInstance(Object target) { this.target target; Enhancer enhancer new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println(CGLib前置处理); Object result proxy.invokeSuper(obj, args); System.out.println(CGLib后置处理); return result; } } // 使用CGLib代理 UserServiceImpl userService (UserServiceImpl) new CglibProxy().getInstance(new UserServiceImpl()); userService.saveUser(李四);CGLib特点可以代理普通类不要求实现接口通过生成子类的方式实现代理性能比JDK动态代理更好在较新JVM上需要引入第三方库4. 静态代理与动态代理的对比分析4.1 实现方式对比对比维度静态代理动态代理创建时机编译期运行期代理类来源手动编写自动生成代码量多每个代理类都需要单独编写少统一处理逻辑维护成本高接口变化需要修改所有代理类低只需修改处理器逻辑4.2 性能对比在性能方面静态代理通常最优因为没有运行时生成类的开销方法调用是直接的没有反射开销动态代理中JDK动态代理由于使用反射调用性能稍差CGLib代理在生成代理类后方法调用通过方法索引直接定位性能接近静态代理实际测试数据百万次调用耗时静态代理约50msCGLib代理约80msJDK动态代理约120ms4.3 适用场景对比选择静态代理当代理类数量少且稳定需要极致性能代理逻辑简单且固定选择动态代理当需要代理大量类代理逻辑复杂或可能变化目标对象可能动态变化需要AOP编程如Spring AOP5. 实际应用中的经验与技巧5.1 代理模式的最佳实践接口设计原则为需要代理的类设计清晰的接口接口方法粒度要适中不宜过大或过小考虑将代理相关的方法集中定义性能优化技巧对于高频调用的方法考虑使用静态代理在动态代理中缓存Method对象避免重复查找对于不需要代理的方法可以在InvocationHandler中做短路处理线程安全考虑代理对象通常是多线程共享的确保InvocationHandler的实现是线程安全的避免在代理逻辑中使用共享可变状态5.2 常见问题与解决方案问题1动态代理导致栈溢出现象在invoke方法中又调用了代理对象的方法形成递归调用解决确保在invoke方法中调用的是原始对象的方法而非代理对象的方法问题2CGLib代理final方法失效现象final方法无法被代理因为CGLib通过继承实现代理解决避免为final方法添加代理逻辑或改用其他方式实现功能增强问题3JDK动态代理接口变化现象接口新增方法后代理类没有实现新方法解决重新生成代理对象或使用更灵活的代理方案5.3 Spring框架中的代理实现Spring框架广泛使用了代理模式特别是其AOP功能。Spring会根据目标对象的情况自动选择代理方式JDK动态代理当目标对象实现了接口时使用CGLib代理当目标对象没有实现接口时使用Spring代理配置技巧使用proxy-target-classtrue强制使用CGLib通过Scope(proxyMode...)指定代理方式注意final方法和private方法无法被代理// Spring AOP代理示例 Configuration EnableAspectJAutoProxy(proxyTargetClass true) public class AppConfig { // 配置类 } Aspect Component public class LoggingAspect { Before(execution(* com.example.service.*.*(..))) public void logBefore(JoinPoint joinPoint) { System.out.println(准备执行: joinPoint.getSignature()); } }在实际项目开发中理解代理模式的实现原理和适用场景能够帮助我们更好地设计和实现系统功能特别是在需要横切关注点如日志、事务、安全等处理的场景下代理模式提供了一种优雅的解决方案。