代理模式核心概念
代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,在不改变原始类代码的情况下增加额外的功能。
代理模式主要分为三种角色:
- Subject:定义真实对象和代理对象的共同接口
- RealSubject:真实处理业务的目标对象
- Proxy:包含对真实对象的引用,可以控制和增强真实对象的行为
静态代理:编译时确定
静态代理需要手动创建代理类,在编译时就已经确定代理关系。
// 共同接口
interface Image {
void display();
}
// 真实对象
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading " + filename);
}
@Override
public void display() {
System.out.println("Displaying " + filename);
}
}
// 代理类
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
// 前置处理
System.out.println("Proxy: Before display");
realImage.display();
// 后置处理
System.out.println("Proxy: After display");
}
}
// 使用示例
public class StaticProxyDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
image.display(); // 真实对象此时才创建
}
}
静态代理的缺点是需要为每个目标类创建代理类,当接口增加方法时,目标和代理都需要修改。
JDK动态代理:运行时动态生成
JDK动态代理利用Java反射机制,在运行时动态生成代理类。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 调用处理器
class LoggingHandler implements InvocationHandler {
private Object target;
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置处理
System.out.println("调用方法: " + method.getName());
// 调用真实对象的方法
Object result = method.invoke(target, args);
// 后置处理
System.out.println("方法调用完成: " + method.getName());
return result;
}
}
// 使用示例
public class JdkDynamicProxyDemo {
public static void main(String[] args) {
// 创建真实对象
Image realImage = new RealImage("test.jpg");
// 创建代理对象
Image proxyImage = (Image) Proxy.newProxyInstance(
Image.class.getClassLoader(),
new Class[]{Image.class},
new LoggingHandler(realImage)
);
proxyImage.display();
}
}
JDK动态代理要求目标类必须实现接口,代理对象是在运行时根据接口动态生成的。
CGLib动态代理:无需接口的方案
CGLib通过字节码技术生成目标类的子类来实现代理,不需要目标类实现接口。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class CglibProxyFactory implements MethodInterceptor {
private Object target;
public CglibProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
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代理: 开始执行 " + method.getName());
Object result = method.invoke(target, args);
System.out.println("CGLib代理: 执行完成 " + method.getName());
return result;
}
}
// 使用示例
public class CglibProxyDemo {
public static void main(String[] args) {
RealImage target = new RealImage("test.jpg");
RealImage proxy = (RealImage) new CglibProxyFactory(target).getProxyInstance();
proxy.display();
}
}
CGLib创建的代理对象性能通常比JDK动态代理更高,但不能代理final类和final方法。
三种代理方式对比
|
特性 |
静态代理 |
JDK动态代理 |
CGLib动态代理 |
|
编译时要求 |
需要显式创建代理类 |
需要接口 |
不需要接口 |
|
性能 |
一般 |
较差(反射开销) |
较高(字节码增强) |
|
灵活性 |
低 |
高 |
高 |
|
依赖 |
无特殊依赖 |
Java标准库 |
需要CGLib库 |
实际应用场景
代理模式在现实项目中有广泛应用:
- Spring AOP:基于动态代理实现面向切面编程
- Hibernate延迟加载:使用代理实现数据的懒加载
- RPC框架:客户端使用代理透明调用远程服务
- 安全代理:控制对敏感对象的访问权限
- 日志记录:在方法调用前后添加日志功能
总结
代理模式是Java设计中极为重要的结构型模式,它通过引入代理对象实现对真实对象的间接访问,从而可以在不修改原有代码的情况下增强功能。根据具体需求,可以选择静态代理、JDK动态代理或CGLib动态代理,每种方式都有其适用场景和优缺点。
掌握代理模式不仅有助于写出更加灵活和可维护的代码,也是理解Spring等主流框架实现原理的基础。在实际开发中,应根据项目需求选择最合适的代理方式,平衡灵活性、性能和复杂度。
1024

被折叠的 条评论
为什么被折叠?



