代理模式实现,静态,动态

一、代理模式核心概念

代理模式是一种结构型设计模式,核心思想是通过一个 "代理类" 来控制对 "目标类" 的访问,代理类可以在不修改目标类代码的前提下,为目标类添加额外功能(如日志、权限校验、性能监控等)。代理模式中主要包含 3 个角色:

  1. 目标对象(Real Subject):真正执行业务逻辑的类。
  2. 代理对象(Proxy):持有目标对象的引用,对外提供与目标对象相同的接口,在调用目标对象方法前后可以扩展逻辑。
  3. 抽象主题(Subject):目标对象和代理对象共同实现的接口(或继承的抽象类),定义核心业务方法。

二、静态代理

1. 定义

静态代理是指代理类在编译期就已经确定(由程序员手动编写代理类代码),代理类和目标类都实现同一个接口,代理类直接持有目标类的实例。

2. 代码示例

步骤 1:定义抽象主题接口(Subject)

java

运行

复制代码
// 抽象主题:订单服务接口
public interface OrderService {
    void createOrder(String orderId);
}

步骤 2:实现目标类(Real Subject)

java

运行

复制代码
// 目标类:真正处理订单的业务类
public class OrderServiceImpl implements OrderService {
    @Override
    public void createOrder(String orderId) {
        System.out.println("创建订单:" + orderId); // 核心业务逻辑
    }
}

步骤 3:编写静态代理类(Proxy)

java

运行

复制代码
// 静态代理类:扩展日志功能
public class OrderServiceProxy implements OrderService {
    // 持有目标对象引用
    private final OrderService target;

    // 通过构造器注入目标对象
    public OrderServiceProxy(OrderService target) {
        this.target = target;
    }

    @Override
    public void createOrder(String orderId) {
        // 前置增强:调用目标方法前添加日志
        System.out.println("【静态代理】创建订单前,记录日志:准备创建订单 " + orderId);
        // 调用目标对象的核心方法
        target.createOrder(orderId);
        // 后置增强:调用目标方法后添加逻辑
        System.out.println("【静态代理】创建订单后,记录日志:订单 " + orderId + " 创建成功");
    }
}

步骤 4:测试静态代理

java

运行

复制代码
public class StaticProxyTest {
    public static void main(String[] args) {
        // 1. 创建目标对象
        OrderService target = new OrderServiceImpl();
        // 2. 创建代理对象,传入目标对象
        OrderService proxy = new OrderServiceProxy(target);
        // 3. 通过代理对象调用方法(实际执行目标方法+扩展逻辑)
        proxy.createOrder("ORDER_001");
    }
}

输出结果

plaintext

复制代码
【静态代理】创建订单前,记录日志:准备创建订单 ORDER_001
创建订单:ORDER_001
【静态代理】创建订单后,记录日志:订单 ORDER_001 创建成功
3. 静态代理的特点
  • 优点:实现简单、逻辑清晰,不修改目标类代码即可扩展功能,符合 "开闭原则"。
  • 缺点
    1. 代理类与目标类一一对应,若有多个目标类需要代理,需编写大量代理类,代码冗余。
    2. 若抽象主题接口新增方法,目标类和所有代理类都需修改,维护成本高。

三、动态代理

1. 定义

动态代理是指代理类在运行期动态生成 (无需手动编写代理类代码),JDK 通过java.lang.reflect.ProxyInvocationHandler实现动态代理,核心是反射机制。

2. 核心 API

表格

类 / 接口 作用
InvocationHandler 回调接口,定义代理类的增强逻辑(invoke 方法)。
Proxy.newProxyInstance 静态方法,生成代理类实例,参数:类加载器、目标类实现的接口、InvocationHandler。
3. 代码示例(JDK 动态代理)

步骤 1:复用抽象主题和目标类(同静态代理的 OrderService、OrderServiceImpl)

步骤 2:编写 InvocationHandler 实现类(定义增强逻辑)

java

运行

复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

// 动态代理的增强逻辑处理器
public class LogInvocationHandler implements InvocationHandler {
    // 持有目标对象(通用类型,适配所有目标类)
    private final Object target;

    public LogInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 代理类调用方法时,会回调此方法
     * @param proxy 代理对象本身(一般不用)
     * @param method 目标方法(被调用的方法)
     * @param args 目标方法的参数
     * @return 目标方法的返回值
     * @throws Throwable 目标方法抛出的异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强:日志记录
        System.out.println("【动态代理】调用方法前:" + method.getName() + ",参数:" + (args != null ? args[0] : ""));
        // 调用目标对象的核心方法
        Object result = method.invoke(target, args);
        // 后置增强:日志记录
        System.out.println("【动态代理】调用方法后:" + method.getName() + ",返回值:" + result);
        return result;
    }
}

步骤 3:测试动态代理

java

运行

复制代码
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
    public static void main(String[] args) {
        // 1. 创建目标对象
        OrderService target = new OrderServiceImpl();
        // 2. 创建InvocationHandler,传入目标对象
        InvocationHandler handler = new LogInvocationHandler(target);
        // 3. 动态生成代理类实例
        OrderService proxy = (OrderService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), // 目标类的类加载器
                target.getClass().getInterfaces(),  // 目标类实现的接口(代理类会实现这些接口)
                handler                              // 增强逻辑处理器
        );
        // 4. 通过代理对象调用方法
        proxy.createOrder("ORDER_002");
    }
}

输出结果

plaintext

复制代码
【动态代理】调用方法前:createOrder,参数:ORDER_002
创建订单:ORDER_002
【动态代理】调用方法后:createOrder,返回值:null
4. 动态代理的特点
  • 优点
    1. 无需手动编写代理类,一个 InvocationHandler 可适配多个目标类,解决静态代理代码冗余问题。
    2. 接口新增方法时,无需修改代理相关代码,维护成本低。
  • 缺点
    1. JDK 动态代理只能代理实现了接口的类(无法代理普通类)。
    2. 基于反射实现,性能略低于静态代理(但日常开发中性能差异可忽略)。
5. 扩展:CGLIB 动态代理

若目标类未实现任何接口,可使用 CGLIB(Code Generation Library)实现动态代理(底层通过 ASM 字节码生成框架生成子类):

java

运行

复制代码
// 需引入CGLIB依赖(Maven)
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

// CGLIB代理示例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// 目标类(无需实现接口)
public class UserService {
    public void addUser(String username) {
        System.out.println("添加用户:" + username);
    }
}

// CGLIB增强处理器
public class CglibLogInterceptor implements MethodInterceptor {
    private final Object target;

    public CglibLogInterceptor(Object target) {
        this.target = target;
    }

    @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;
    }
}

// 测试CGLIB代理
public class CglibProxyTest {
    public static void main(String[] args) {
        UserService target = new UserService();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class); // 设置父类(目标类)
        enhancer.setCallback(new CglibLogInterceptor(target)); // 设置增强逻辑
        UserService proxy = (UserService) enhancer.create(); // 生成代理对象
        proxy.addUser("张三");
    }
}

四、静态代理 vs 动态代理对比

表格

维度 静态代理 动态代理(JDK)
代理类生成时机 编译期(手动编写) 运行期(反射动态生成)
代码冗余度 高(一个目标类对应一个代理类) 低(一个处理器适配多个目标类)
接口依赖 依赖(代理类和目标类实现同一接口) 依赖(仅能代理实现接口的类)
维护成本 高(接口变更需修改所有代理类) 低(接口变更无需修改代理逻辑)
性能 略高(直接调用) 略低(反射调用)
相关推荐
逆境不可逃3 小时前
【从零入门23种设计模式12】结构型之代理模式(Spring AOP + 自定义注解 + 切面的实战)
设计模式·代理模式
一碗烈酒14 小时前
【使用Python临时搭建代理转发服务,内网穿透】
python·测试工具·代理模式
tsyjjOvO15 小时前
代理模式详解:静态代理、JDK 动态代理、CGLIB 动态代理
java·开发语言·代理模式
柒.梧.15 天前
Java代理模式精讲:静态代理+JDK动态代理
java·开发语言·代理模式
Forget_855016 天前
RHEL——HAProxy模式
代理模式
mjhcsp19 天前
C++ 树形 DP解析
开发语言·c++·动态规划·代理模式
不想看见40419 天前
House Robber 基本动态规划:一维--力扣101算法题解笔记
笔记·算法·leetcode·代理模式
忘梓.22 天前
解锁动态规划的奥秘:从零到精通的创新思维解析(10)
c++·算法·动态规划·代理模式
HEU_firejef24 天前
设计模式——代理模式
设计模式·代理模式