代理模式概述
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过代理对象来控制对目标对象的访问。代理模式的核心思想是引入一个中介对象(代理),该代理对象负责控制对实际对象的访问,通常用于增强功能、控制访问权限或延迟初始化等场景。
代理模式的主要角色:
- 抽象主题(Subject):定义代理类和实际类的公共接口。
- 真实主题(RealSubject):实现了实际业务逻辑的类。
- 代理(Proxy):控制对真实对象的访问,可以增加额外的功能。
代理模式主要有两种实现方式:静态代理和动态代理。
1. 静态代理
在静态代理中,代理类和目标类都要实现相同的接口,代理类通过调用目标类的方法来实现功能扩展。
代码示例:
java
复制代码
// 抽象主题接口 public interface Subject { void request(); } // 真实主题类 public class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject: 执行实际业务逻辑..."); } } // 代理类 public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { System.out.println("Proxy: 在调用实际方法前可以做一些处理..."); realSubject.request(); // 调用真实对象的方法 System.out.println("Proxy: 在调用实际方法后可以做一些处理..."); } } // 客户端测试 public class Client { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Proxy proxy = new Proxy(realSubject); proxy.request(); // 通过代理调用方法 } }
输出结果:
makefile
复制代码
Proxy: 在调用实际方法前可以做一些处理... RealSubject: 执行实际业务逻辑... Proxy: 在调用实际方法后可以做一些处理...
静态代理的优缺点:
- 优点:可以在不修改原始类的前提下增加功能。
- 缺点:每增加一个代理类都需要手动编写,代码量随之增加。
2. 动态代理
动态代理是代理模式的进化版,不需要为每个类手动编写代理类。动态代理在运行时生成代理对象,可以在运行时对方法进行增强。
在 Java 中,动态代理可以通过 JDK
的反射机制或 CGLIB
实现。
JDK 动态代理
JDK 提供了 java.lang.reflect.Proxy
类来创建动态代理,但它只能代理实现了接口的类。
代码示例:
java
复制代码
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 抽象主题接口 public interface Subject { void request(); } // 真实主题类 public class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject: 执行实际业务逻辑..."); } } // 动态代理处理器 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("Dynamic Proxy: 在方法调用前可以做一些处理..."); Object result = method.invoke(target, args); // 调用真实对象的方法 System.out.println("Dynamic Proxy: 在方法调用后可以做一些处理..."); return result; } } // 客户端测试 public class Client { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); // 创建动态代理对象 Subject proxy = (Subject) Proxy.newProxyInstance( realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new DynamicProxyHandler(realSubject)); // 通过代理调用方法 proxy.request(); } }
输出结果:
yaml
复制代码
Dynamic Proxy: 在方法调用前可以做一些处理... RealSubject: 执行实际业务逻辑... Dynamic Proxy: 在方法调用后可以做一些处理...
JDK 动态代理的优缺点:
- 优点:不需要为每个类编写代理类,节省代码量。
- 缺点:只能代理实现了接口的类,无法代理普通类。
3. CGLIB 动态代理
CGLIB 是另一个用于实现动态代理的库,它通过生成目标类的子类来实现代理,能够代理没有实现接口的类。
CGLIB 代理示例:
java
复制代码
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; // 真实主题类(没有实现接口) public class RealSubject { public void request() { System.out.println("RealSubject: 执行实际业务逻辑..."); } } // CGLIB 代理拦截器 public class CglibProxy implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("CGLIB Proxy: 在方法调用前可以做一些处理..."); Object result = proxy.invokeSuper(obj, args); // 调用真实对象的方法 System.out.println("CGLIB Proxy: 在方法调用后可以做一些处理..."); return result; } } // 客户端测试 public class Client { public static void main(String[] args) { // 创建 CGLIB 代理对象 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealSubject.class); enhancer.setCallback(new CglibProxy()); RealSubject proxy = (RealSubject) enhancer.create(); proxy.request(); // 通过代理调用方法 } }
输出结果:
yaml
复制代码
CGLIB Proxy: 在方法调用前可以做一些处理... RealSubject: 执行实际业务逻辑... CGLIB Proxy: 在方法调用后可以做一些处理...
CGLIB 动态代理的优缺点:
- 优点:可以代理没有实现接口的类。
- 缺点:由于是通过继承的方式代理,无法代理
final
类和final
方法。
代理模式应用场景
- 权限控制:通过代理类来控制对某些敏感对象的访问权限。
- 性能优化:在代理中加入缓存逻辑,避免频繁调用开销大的方法。
- 延迟加载:在需要时才创建实际对象,以节省资源。
代理模式的灵活性很高,可以适用于各种场景,包括权限管理、日志记录、事务处理等。
目录