当前位置: 首页 > news >正文

Java 代理模式:从静态代理到动态代理

前言

        代理模式是 Java 中常见的设计模式之一,它的核心思想是通过一个代理对象来控制对真实对象的访问。代理模式不仅可以扩展目标对象的功能,而且在不修改原目标对象的情况下,可以增加一些我们自定义的操作。

1. 代理模式简介

        代理模式的核心思想是:通过代理对象来代替对真实对象的访问。这样做的好处是,我们可以在不修改原目标对象的前提下,扩展目标对象的功能。比如,在目标对象的某个方法执行前后,你可以增加一些自定义的操作。

举个例子:

新娘找来了自己的闺蜜来代替自己处理新郎的提问。新娘收到的提问都是经过闺蜜处理过滤之后的。闺蜜在这里就可以看作是新娘的代理对象,代理的行为(方法)是接收和回复新郎的提问。

再举个例子:

你是一个明星,每天有很多粉丝找你签名。但你是大忙人,没时间亲自处理这些请求,所以你找了一个经纪人(代理对象)来帮你处理。粉丝的请求先交给经纪人,经纪人再决定是否转交给你,或者帮你做一些额外的处理(比如记录谁来找你签名)。这样,你既不用亲自处理所有请求,又能保证签名工作顺利进行。

2. 静态代理

2.1 什么是静态代理?

        静态代理是指,在编译时就已经确定了代理类和目标类的关系。我们需要手动为每个目标类创建一个代理类,并在代理类中调用目标类的方法。

        静态代理的缺点:灵活性较差,一旦接口新增方法,目标类和代理类都需要进行修改。

2.2 静态代理的实现步骤

  1. 定义一个接口及其实现类
  2. 创建一个代理类并实现该接口
  3. 将目标对象注入代理类,并在代理类的方法中调用目标类的方法

2.3 代码示例

1. 定义发送短信的接口
public interface SmsService {
    String send(String message);
}
2. 实现发送短信的接口
public class SmsServiceImpl implements SmsService {
    public String send(String message) {
        System.out.println("send message:" + message);
        return message;
    }
}
3. 创建代理类并实现发送短信的接口
public class SmsProxy implements SmsService {

    private final SmsService smsService;

    public SmsProxy(SmsService smsService) {
        this.smsService = smsService;
    }

    @Override
    public String send(String message) {
        // 调用方法之前,我们可以添加自己的操作
        System.out.println("before method send()");
        smsService.send(message);
        // 调用方法之后,我们同样可以添加自己的操作
        System.out.println("after method send()");
        return null;
    }
}
4. 实际使用
public class Main {
    public static void main(String[] args) {
        SmsService smsService = new SmsServiceImpl();
        SmsProxy smsProxy = new SmsProxy(smsService);
        smsProxy.send("java");
    }
}

运行上述代码之后,控制台打印出:

before method send()
send message:java
after method send()

可以看到,我们成功地在 SmsServiceImpl 的 send() 方法前后增加了自定义操作。

3. 动态代理

3.1 什么是动态代理?

        相比于静态代理,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,而是可以在运行时动态生成代理类。动态代理的实现方式有很多种,比如 JDK 动态代理和 CGLIB 动态代理。

3.2 JDK 动态代理

3.2.1 JDK 动态代理的核心

        在 JDK 动态代理中,InvocationHandler 接口和 Proxy 类是核心。Proxy 类的 newProxyInstance() 方法用于生成代理对象,而 InvocationHandler 接口的 invoke() 方法则用于处理代理对象的方法调用。

3.2.2 JDK 动态代理的实现步骤
  1. 定义一个接口及其实现类
  2. 自定义 InvocationHandler 并重写 invoke 方法
  3. 通过 Proxy.newProxyInstance() 方法创建代理对象
3.2.3 代码示例
1. 定义发送短信的接口
public interface SmsService {
    String send(String message);
}
2. 实现发送短信的接口
public class SmsServiceImpl implements SmsService {
    public String send(String message) {
        System.out.println("send message:" + message);
        return message;
    }
}
3. 定义一个 JDK 动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DebugInvocationHandler implements InvocationHandler {
    private final Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before method " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("after method " + method.getName());
        return result;
    }
}
4. 获取代理对象的工厂类
import java.lang.reflect.Proxy;

public class JdkProxyFactory {
    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new DebugInvocationHandler(target)
        );
    }
}
5. 实际使用
public class Main {
    public static void main(String[] args) {
        SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
        smsService.send("java");
    }
}

运行上述代码之后,控制台打印出:

before method send
send message:java
after method send

3.3 CGLIB 动态代理

3.3.1 CGLIB 动态代理的核心

        CGLIB 动态代理通过继承目标类来生成代理类,因此它可以代理未实现任何接口的类。CGLIB 的核心是 MethodInterceptor 接口和 Enhancer 类。

3.3.2 CGLIB 动态代理的实现步骤
  1. 定义一个类
  2. 自定义 MethodInterceptor 并重写 intercept 方法
  3. 通过 Enhancer 类的 create() 方法创建代理类
3.3.3 代码示例
1. 实现一个使用阿里云发送短信的类
public class AliSmsService {
    public String send(String message) {
        System.out.println("send message:" + message);
        return message;
    }
}
2. 自定义 MethodInterceptor
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class DebugMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before method " + method.getName());
        Object object = methodProxy.invokeSuper(o, args);
        System.out.println("after method " + method.getName());
        return object;
    }
}
3. 获取代理类
import net.sf.cglib.proxy.Enhancer;

public class CglibProxyFactory {
    public static Object getProxy(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(clazz.getClassLoader());
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new DebugMethodInterceptor());
        return enhancer.create();
    }
}
4. 实际使用
public class Main {
    public static void main(String[] args) {
        AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
        aliSmsService.send("java");
    }
}

运行上述代码之后,控制台打印出:

before method send
send message:java
after method send

4. 静态代理和动态代理的对比

  • 灵活性:动态代理更加灵活,不需要针对每个目标类都创建一个代理类,且可以直接代理实现类。
  • JVM 层面:静态代理在编译时生成 class 文件,而动态代理在运行时动态生成类字节码。

相关文章:

  • DeepSeek:为教培小程序赋能,引领行业变革新潮流
  • 基于STM32的火灾报警设备(阿里云平台)
  • Oracle Database 11g、12c、18c、19c、21c、22c 与 23AI 各版本差异、优缺点详解
  • 【Node.js入门笔记6---fs流(Streams)与管道(Pipe)】
  • 使用 Doris 和 Hudi
  • JVM 如何保证 Java 程序的安全性?
  • 共享内存的通信
  • css模拟雷达扫描动画
  • 新办公室哪款空气净化器除甲醛效果好?高效除甲醛,提升效率
  • 【算法设计与分析】算法概论
  • 使用Redis如何实现分布式锁?(超卖)
  • JVM的各种细节
  • android 新闻客户端和springboot后台开发(一)
  • 如何处理PHP中的日期和时间问题
  • Node.js REPL 深入解析
  • OTSU算法(大津算法)
  • DeepSeek技术解析:MoE架构实现与代码实战
  • Python高级算法与数据结构优化实战
  • 网络质量分析(NQA) 技术详解:原理、应用与配置实践
  • 51c大模型~合集7
  • 出走的苏敏阿姨一路走到了戛纳,这块红毯因她而多元
  • 乌克兰谈判代表团由12人组成,乌防长率领
  • 布局50多个国家和地区,我国科技型企业孵化器数量全球第一
  • 普京召开俄乌谈判筹备会议,拉夫罗夫、绍伊古等出席
  • 泰山、华海、中路等山东险企综合成本率均超100%,承保业务均亏损
  • 机构发布“2025中国高职院校排名”