设计模式5-代理模式
定义
Proxy Partern:为其他对象提供一种代理以控制对这个对象的访问。
目的
● 保护原始对象
● 解耦合(代理类中增加缓存操作、增加业务逻辑)
场景
-
Collections框架:
unmodifiableXXX
,synchronizedXXX
,checkedXXX
-
RMI:远程方法调用的stub和skeleton
-
Spring框架:AOP、事务管理、安全控制
-
Java EE:EJB、CDI、JPA的延迟加载
-
数据库连接池:连接管理、资源池化
-
安全框架:权限检查、访问控制
分类
静态代理
// 接口
interface UserService {void addUser(String name);String getUser(int id);
}// 实现类
class UserServiceImpl implements UserService {public void addUser(String name) {System.out.println("添加用户: " + name);}public String getUser(int id) {return "用户" + id;}
}// 静态代理类
class UserServiceStaticProxy implements UserService {private UserService target;public UserServiceStaticProxy(UserService target) {this.target = target;}public void addUser(String name) {System.out.println("【静态代理】前置处理");target.addUser(name);System.out.println("【静态代理】后置处理");}public String getUser(int id) {System.out.println("【静态代理】前置处理");String result = target.getUser(id);System.out.println("【静态代理】后置处理");return result;}
}
动态代理
JDK动态代理
JDK动态代理是Java标准库内置的代理实现,基于接口的代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;//集合只读类
public class JDKProxyExamples {// 创建只读List的代理public static <T> List<T> createReadOnlyList(List<T> originalList) {return (List<T>) Proxy.newProxyInstance(originalList.getClass().getClassLoader(),originalList.getClass().getInterfaces(),new ReadOnlyInvocationHandler(originalList));}static class ReadOnlyInvocationHandler implements InvocationHandler {private final Object target;public ReadOnlyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();// 拦截修改操作if (methodName.startsWith("add") || methodName.startsWith("remove") || methodName.startsWith("set") || methodName.startsWith("clear")) {throw new UnsupportedOperationException("只读集合,不支持修改操作");}// 允许读操作return method.invoke(target, args);}}public static void main(String[] args) {List<String> originalList = new ArrayList<>();originalList.add("Java");originalList.add("Python");originalList.add("C++");List<String> readOnlyList = createReadOnlyList(originalList);System.out.println("原始列表: " + originalList);System.out.println("只读代理列表: " + readOnlyList);// 读操作正常System.out.println("第一个元素: " + readOnlyList.get(0));System.out.println("列表大小: " + readOnlyList.size());try {// 写操作会抛出异常readOnlyList.add("JavaScript");} catch (Exception e) {System.out.println("写操作异常: " + e.getMessage());}}
}
CGLIB动态代理
基于cglib库来实现(非jdk原生),需要引入第三方类库
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;/*** CGLIB方法拦截器
* 添加maven依赖
* MAVEN download sources下即可
* <dependencies>
* <dependency>
* <groupId>cglib</groupId>
* <artifactId>cglib</artifactId>
* <version>3.3.0</version>
* </dependency>
* </dependencies>*/
public class CglibMethodInterceptor implements MethodInterceptor {private Object target;public CglibMethodInterceptor(Object target) {this.target = target;}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {String methodName = method.getName();// 过滤掉Object类的方法(如toString, hashCode等)if (Object.class.equals(method.getDeclaringClass())) {return proxy.invokeSuper(obj, args);}// 过滤final方法和static方法if (methodName.equals("getServiceInfo") || methodName.equals("getVersion")) {System.out.println("【CGLIB】跳过final/static方法: " + methodName);return method.invoke(target, args);}System.out.println("【CGLIB代理】前置处理 - 方法: " + methodName);try {// 调用目标方法Object result = proxy.invoke(target, args);System.out.println("【CGLIB代理】后置处理 - 方法: " + methodName + ", 结果: " + result);return result;} catch (Exception e) {System.out.println("【CGLIB代理】异常处理 - 方法: " + methodName + ", 异常: " + e.getMessage());throw e;} finally {System.out.println("【CGLIB代理】最终处理 - 方法: " + methodName);}}
}/*** CGLIB代理工厂*/
class CglibProxyFactory {/*** 创建代理对象(使用默认构造函数)*/public static <T> T createProxy(Class<T> targetClass) {return createProxy(targetClass, null, null);}/*** 创建代理对象(带参数)*/public static <T> T createProxy(Class<T> targetClass, Class<?>[] argumentTypes, Object[] arguments) {Enhancer enhancer = new Enhancer();// 设置父类(被代理的类)enhancer.setSuperclass(targetClass);// 设置回调拦截器enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("【CGLIB通用代理】方法调用: " + method.getName());return proxy.invokeSuper(obj, args);}});// 创建代理对象if (argumentTypes != null && arguments != null) {return (T) enhancer.create(argumentTypes, arguments);} else {return (T) enhancer.create();}}/*** 创建带有自定义拦截器的代理对象*/public static <T> T createProxyWithInterceptor(Class<T> targetClass, MethodInterceptor interceptor) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setCallback(interceptor);return (T) enhancer.create();}
}
对比
特性 | 静态代理 | JDK动态代理 | CGLIB动态代理 |
---|---|---|---|
实现方式 | 手动编写代理类 | 基于接口,使用Proxy 和InvocationHandler | 基于继承,使用字节码技术 |
依赖 | 无特殊依赖 | Java标准库 | 需要cglib库依赖 |
目标要求 | 需要接口或具体类 | 必须基于接口 | 可以代理具体类(无需接口) |
性能 | 较高(直接调用) | 中等(反射调用) | 较高(方法索引调用) |
生成方式 | 编译时生成 | 运行时生成代理类 | 运行时生成子类 |
方法拦截 | 硬编码在代理类中 | 通过InvocationHandler 统一处理 | 通过MethodInterceptor 统一处理 |
final方法 | 可以代理 | 可以代理(通过接口) | 无法代理(final方法不能重写) |
构造函数 | 可自定义 | 只能使用无参构造 | 可处理有参构造 |
使用复杂度 | 高(每个类需要单独代理) | 中(统一处理逻辑) | 中(统一处理逻辑) |
代码示例 | 需要为每个接口写实现 | 使用Proxy.newProxyInstance() | 使用Enhancer.create() |
实例
房东(House)、租客(Client)、中介(Proxy)
假如你是一个房东,不想与租客进行打交道,这时候可以代理给中介(proxy)让中介处理租房事宜,房东只需要根据中介打交道即可。
import java.util.HashMap;
import java.util.Map;// 抽象主题接口
interface RentalService {void rentHouse(String clientName, Map<String, Object> houseDetails);Map<String, Object> showHouse(String houseId);
}// 真实主题:房东
class HouseOwner implements RentalService {private Map<String, Map<String, Object>> houses;public HouseOwner() {houses = new HashMap<>();Map<String, Object> house1 = new HashMap<>();house1.put("location", "市中心");house1.put("price", 3000);house1.put("size", "80平米");Map<String, Object> house2 = new HashMap<>();house2.put("location", "郊区");house2.put("price", 2000);house2.put("size", "100平米");houses.put("001", house1);houses.put("002", house2);}@Overridepublic void rentHouse(String clientName, Map<String, Object> houseDetails) {System.out.println("房东直接与" + clientName + "签订合同,租赁" + houseDetails.get("location") + "的房屋");System.out.println("月租: " + houseDetails.get("price") + "元, 面积: " + houseDetails.get("size"));}@Overridepublic Map<String, Object> showHouse(String houseId) {return houses.get(houseId);}
}// 代理:中介
class HouseAgent implements RentalService {private HouseOwner houseOwner;private double commissionRate = 0.1;public HouseAgent(HouseOwner houseOwner) {this.houseOwner = houseOwner;}@Overridepublic Map<String, Object> showHouse(String houseId) {System.out.println("中介带看房屋" + houseId);return houseOwner.showHouse(houseId);}@Overridepublic void rentHouse(String clientName, Map<String, Object> houseDetails) {// 中介添加额外服务System.out.println("中介为" + clientName + "提供专业咨询服务");System.out.println("中介协助" + clientName + "检查房屋状况");// 计算中介费int price = (Integer) houseDetails.get("price");double commission = price * commissionRate;System.out.println("中介代表房东与" + clientName + "签订合同");System.out.println("租赁" + houseDetails.get("location") + "的房屋");System.out.println("月租: " + price + "元, 中介费: " + commission + "元/月, 面积: " + houseDetails.get("size"));// 实际调用房东的租赁方法houseOwner.rentHouse(clientName, houseDetails);}
}// 客户端:租客
class Tenant {private String name;public Tenant(String name) {this.name = name;}public void findHouseThroughAgent(HouseAgent agent, String houseId) {System.out.println(name + "通过中介寻找房屋");Map<String, Object> houseDetails = agent.showHouse(houseId);if (houseDetails != null) {agent.rentHouse(name, houseDetails);} else {System.out.println("未找到合适的房屋");}}public void findHouseDirectly(HouseOwner houseOwner, String houseId) {System.out.println(name + "直接联系房东寻找房屋");Map<String, Object> houseDetails = houseOwner.showHouse(houseId);if (houseDetails != null) {houseOwner.rentHouse(name, houseDetails);} else {System.out.println("未找到合适的房屋");}}
}// 使用示例
public class ProxyPatternExample {public static void main(String[] args) {// 创建房东HouseOwner houseOwner = new HouseOwner();// 创建中介(代理)HouseAgent agent = new HouseAgent(houseOwner);// 创建租客Tenant tenant = new Tenant("张三");System.out.println("=== 租客通过中介租房 ===");tenant.findHouseThroughAgent(agent, "001");System.out.println("\n=== 租客直接联系房东租房 ===");tenant.findHouseDirectly(houseOwner, "002");}
}
代理模式代码