代理模式(Proxy Pattern)是软件设计模式中的一种,它为其他对象提供一个代理以控制对这个对象的访问。在代理模式中,代理类负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息。代理模式可以用来实现延迟加载、日志记录、权限控制等功能。
代理模式的类型
- 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机上,也可以是在另一台主机上。
- 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象,通过使用一个小对象来代表一个大对象,从而减少实际对象的创建次数。
- 保护代理(Protection Proxy):控制对原始对象的访问,用于对象有不同的访问权限。
- 智能引用(Smart Reference):当一个对象被引用时,提供额外的操作,比如记录对象被访问的次数等。
代理模式的结构
- Subject(主题接口):定义了RealSubject和Proxy的共同接口,这样在任何使用RealSubject的地方都可以使用Proxy。
- RealSubject(真实主题):定义了代理所代表的真实对象。
- Proxy(代理):保存一个引用使得代理可以访问真实主题,并提供一个与Subject相同的接口,以便可以在任何使用RealSubject的地方使用Proxy。代理可以在客户端调用传递给真实主题之前或之后执行一些操作。
代理模式的优缺点
优点:
- 职责分离:将服务对象与调用者分离,增加了系统的灵活性。
- 控制访问:可以对访问进行控制,例如权限控制、延迟加载等。
- 增强功能:可以在不改变原始对象的情况下,增加额外的功能,如日志记录、事务处理等。
缺点:
- 复杂度增加:引入代理会使得系统设计更加复杂。
- 性能影响:如果代理处理不当,可能会导致请求处理速度变慢。
优秀框架案例
-
Spring AOP(面向切面编程):
- 介绍:Spring AOP 是 Spring 框架的一部分,用于实现面向切面编程。它允许开发者定义"切面",这些切面可以在多个对象中重用,而无需修改这些对象的代码。Spring AOP 通常用于日志记录、事务管理、安全性等。
- 实现:Spring AOP 使用代理模式来实现切面。对于 Spring 管理的 Bean,可以使用 CGLIB 代理或 JDK 动态代理。CGLIB 代理适用于没有实现接口的类,而 JDK 动态代理适用于实现了接口的类。
-
Hibernate 框架:
- 介绍:Hibernate 是一个 ORM(对象关系映射)框架,用于 Java 应用程序。它允许开发者通过 Java 类来管理关系数据库表,并提供了延迟加载功能。
- 实现:Hibernate 使用代理模式来实现延迟加载。当查询一个对象时,Hibernate 并不会立即加载该对象的所有关联对象,而是返回一个代理对象。只有当访问这些关联对象时,Hibernate 才会真正去数据库中加载数据。
-
Java RMI(远程方法调用):
- 介绍:Java RMI 是 Java 平台提供的一个远程过程调用技术,允许一个 Java 虚拟机中的对象调用另一个 Java 虚拟机中的对象的方法。
- 实现:Java RMI 使用远程代理模式。客户端通过一个远程代理对象来调用服务器端的方法,代理对象负责处理网络通信和方法调用。
-
Apache Shiro:
- 介绍:Apache Shiro 是一个强大且易用的 Java 安全框架,提供了认证、授权、加密和会话管理功能。
- 实现:Shiro 使用保护代理模式来控制对资源的访问。通过代理对象,Shiro 可以在用户访问资源之前进行权限检查,确保用户有相应的权限。
示例代码
以下是一个简单的 Java 代理模式示例,使用了 JDK 动态代理:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义一个接口
interface Service {
void doSomething();
}
// 实现该接口的真实对象
class RealService implements Service {
@Override
public void doSomething() {
System.out.println("RealService is doing something.");
}
}
// 定义一个代理类,实现了 InvocationHandler 接口
class ServiceProxy implements InvocationHandler {
private final Service realService;
public ServiceProxy(Service realService) {
this.realService = realService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用真实对象的方法之前,可以添加额外的逻辑
System.out.println("Before method call.");
// 调用真实对象的方法
Object result = method.invoke(realService, args);
// 在调用真实对象的方法之后,可以添加额外的逻辑
System.out.println("After method call.");
return result;
}
}
public class ProxyPatternExample {
public static void main(String[] args) {
// 创建真实对象
Service realService = new RealService();
// 创建代理对象
Service proxyService = (Service) Proxy.newProxyInstance(
RealService.class.getClassLoader(),
new Class[]{Service.class},
new ServiceProxy(realService)
);
// 通过代理对象调用方法
proxyService.doSomething();
}
}
在这个示例中,Service
是一个接口,RealService
是实现该接口的真实对象,ServiceProxy
是一个实现了 InvocationHandler
接口的代理类。通过 Proxy.newProxyInstance
方法创建了一个代理对象 proxyService
,当调用 proxyService.doSomething()
时,代理对象会在调用真实对象的方法前后添加额外的逻辑。
总结
代理模式是一种非常灵活的设计模式,广泛应用于各种场景中,如远程调用、延迟加载、权限控制等。通过使用代理模式,可以有效地增强系统的功能和灵活性,同时保持原始对象的独立性。