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 高级全套到此结束:单元测试 → 反射 → 注解 → 动态代理。

相关推荐
高级程序源1 小时前
springboot校园外卖平台13676-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·tomcat·maven·课程设计
垆边人似月.1 小时前
华为题:盛最多水的容器
数据结构·算法
怦然丶心动1 小时前
用 Java 把干支历法算清楚:从节气切年到可读摘要
java·算法·vue·独立开发·spring boot / spring
青春逝如流水1 小时前
Java 线程与操作系统、硬件的关系:状态、映射与差异
java·开发语言·多线程·ai文章
深入云栈1 小时前
Netty 4.2.x 源码深度解析 (十八):ChannelOutboundBuffer 写缓冲区 —— 发送队列与流量控制
java·后端·架构
谢亮_vipxieliang1 小时前
Go gRPC基础与实战
开发语言·后端·golang
我是人✓1 小时前
Java核心术语与内存机制深度解析
java
Zachery Pole1 小时前
具身智能强化学习(1)引言
算法·机器学习
xuxigifxfh1 小时前
面试记录2026
java·mysql·面试·职场和发展