定义
Proxy Partern:为其他对象提供一种代理以控制对这个对象的访问。
目的
● 保护原始对象
● 解耦合(代理类中增加缓存操作、增加业务逻辑)
场景
-
Collections框架:
unmodifiableXXX
,synchronizedXXX
,checkedXXX
-
RMI:远程方法调用的stub和skeleton
-
Spring框架:AOP、事务管理、安全控制
-
Java EE:EJB、CDI、JPA的延迟加载
-
数据库连接池:连接管理、资源池化
-
安全框架:权限检查、访问控制
分类
静态代理
java
// 接口
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标准库内置的代理实现,基于接口的代理。
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;
}
@Override
public 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原生),需要引入第三方类库
java
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;
}
@Override
public 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() {
@Override
public 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)让中介处理租房事宜,房东只需要根据中介打交道即可。
java
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);
}
@Override
public void rentHouse(String clientName, Map<String, Object> houseDetails) {
System.out.println("房东直接与" + clientName + "签订合同,租赁" +
houseDetails.get("location") + "的房屋");
System.out.println("月租: " + houseDetails.get("price") +
"元, 面积: " + houseDetails.get("size"));
}
@Override
public 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;
}
@Override
public Map<String, Object> showHouse(String houseId) {
System.out.println("中介带看房屋" + houseId);
return houseOwner.showHouse(houseId);
}
@Override
public 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");
}
}