JavaSE高级:动态代理

一、代理思想

代理:找一个代理对象,代替目标对象干活,在目标方法执行前后,增加额外功能(增强),不修改目标类源码。

举例:租房,你是目标对象,中介是代理;中介帮你处理合同、看房(增强逻辑),最后还是调用你租房的核心方法。

  • 目标对象(被代理对象):包含核心业务方法
  • 代理对象:对目标方法做增强,最终调用目标对象原方法

核心好处:不改动原有代码,对方法进行增强(AOP 思想底层原理)

二、静态代理(了解,对比用)

静态代理:代理类代码提前手动写好,编译期就存在代理类。 缺点:

  1. 一个目标类就要写一个代理类,类爆炸
  2. 接口方法增加,代理类代码也要同步修改

动态代理:不用手动写代理类!运行时 JVM 自动动态生成代理类的字节码

三、JDK 动态代理(重点,Java 原生)

✅ 前提:目标对象必须实现接口

JDK 动态代理只能给【实现了接口】的类生成代理对象。

核心 API(java.lang.reflect 包)

  1. Proxy:代理工具类,用来创建代理对象

    java 复制代码
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

    参数说明:

    • ClassLoader loader:类加载器,目标对象的类加载器
    • Class<?>[] interfaces:目标对象实现的接口数组
    • InvocationHandler h:调用处理器,代理对象执行方法时,会触发这个处理器的 invoke 方法
  2. InvocationHandler 接口 唯一抽象方法:invoke(Object proxy, Method method, Object[] args)

    代理对象调用任何方法,都会进入 invoke 方法

    • proxy:生成的代理对象(一般不用)
    • method:当前正在执行的目标方法
    • args:目标方法的参数 返回值:目标方法执行后的返回结果

执行流程

  1. 运行时,JVM 自动生成代理类字节码
  2. 使用Proxy.newProxyInstance()创建代理对象
  3. 代理对象调用方法 → 进入invoke()
  4. 在 invoke 里:执行增强代码 → 调用目标对象原方法 → 后续增强代码

四、完整代码示例

1. 定义接口

java 复制代码
// 业务接口
public interface UserService {
    void addUser();
    void deleteUser();
}

2. 目标类(实现接口)

java 复制代码
//目标对象:核心业务
public class UserServiceImpl implements UserService{
    @Override
    public void addUser() {
        System.out.println("【核心】新增用户");
    }
    @Override
    public void deleteUser() {
        System.out.println("【核心】删除用户");
    }
}

3. 创建代理对象 + 测试

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

public class ProxyTest {
    public static void main(String[] args) {
        //1. 创建目标对象
        UserService target = new UserServiceImpl();

        //2. 生成代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // ========== 前置增强 ==========
                        System.out.println("【增强】日志记录,方法执行前");

                        // 执行目标对象原始方法
                        Object result = method.invoke(target, args);

                        // ========== 后置增强 ==========
                        System.out.println("【增强】日志记录,方法执行后");
                        return result;
                    }
                }
        );

        //3. 通过代理对象调用方法
        proxy.addUser();
        System.out.println("-----------------------");
        proxy.deleteUser();
    }
}

运行结果:

复制代码
【增强】日志记录,方法执行前
【核心】新增用户
【增强】日志记录,方法执行后
-----------------------
【增强】日志记录,方法执行前
【核心】删除用户
【增强】日志记录,方法执行后

五、JDK 动态代理特点

✅ 优点:运行时自动生成代理类,不需要手动写代理代码;灵活 ❌ 限制:目标类必须实现接口,没有接口不能用 JDK 动态代理

拓展:CGLIB 动态代理(第三方):不需要接口,继承目标类生成子类做代理;Spring AOP 底层:优先 JDK 代理,没有接口就用 CGLIB。

六、作用 & 实际开发场景

作用:在不修改目标类源码的前提下,对目标方法做增强。 应用场景:

  1. Spring AOP(面向切面编程):日志、事务、权限校验
  2. MyBatis Mapper 接口:Mapper 没有实现类,底层 JDK 动态代理生成代理对象

七、面试简答背诵版

动态代理:在程序运行期间,JVM 自动生成代理类字节码,创建代理对象。 JDK 动态代理要求目标对象必须实现接口 ,通过Proxy.newProxyInstance()创建代理;代理对象调用方法会触发InvocationHandler的 invoke 方法,在 invoke 内部完成方法增强和目标方法调用。 核心思想:不修改源码,对方法增强。


JavaSE 高级全套到此结束:单元测试 → 反射 → 注解 → 动态代理。

相关推荐
LMT流氓兔32 分钟前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节
专注仿真39 分钟前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法
小豆庄1 小时前
视频遮罩追踪退场后ID撞号的排查—多目标场景下的失效
opencv·算法·bug·视频·python3.11
外收内放1 小时前
Python基础语法练习题(75)
开发语言·python·学习
Tisfy1 小时前
LeetCode 3882.网格图中最小异或路径:动态规划
算法·leetcode·动态规划
starzy19902 小时前
Scala循环与判断:一切皆表达式的控制流
开发语言·人工智能·scala
wangbing11252 小时前
平台介绍-modbus设备调试
java
starzy19902 小时前
Scala类和对象:从构造器到样例类的完整指南
开发语言·后端·scala
niucloud-admin2 小时前
NIUCLOUD PHP SAAS上门家政使用文档--服务订单:订单列表
开发语言·php
D e re k ZH2 小时前
P5025 [SNOI2017] 炸弹
c++·算法