设计模式5-代理模式

定义

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动态代理
实现方式 手动编写代理类 基于接口,使用ProxyInvocationHandler 基于继承,使用字节码技术
依赖 无特殊依赖 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");
    }
}

代理模式代码