JAVA 动态代理

一句话概括:不写死代理类,在程序运行时自动生成代理对象,用来在不修改原代码的前提下,统一加功能(日志、事务、权限、统计等)。


一、两种动态代理

  1. JDK 动态代理

    • 基于 接口
    • 被代理类 必须实现接口
    • Java 原生,无需依赖
  2. CGLIB 动态代理

    • 基于 继承
    • 可以代理 没有接口的类
    • 需要引入 cglib 依赖(Spring 内置)

二、JDK 动态代理(最常用)

核心类

  • InvocationHandler:处理逻辑的接口
  • Proxy.newProxyInstance():生成代理对象

步骤

  1. 定义 接口
  2. 实现类(目标对象)
  3. InvocationHandler 实现类 ,在 invoke 里加增强逻辑
  4. 通过 Proxy 生成代理对象

极简示例

1. 接口

java

运行

复制代码
public interface UserService {
    void add();
}
2. 实现类

java

运行

复制代码
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("添加用户");
    }
}
3. 代理处理器

java

运行

复制代码
public class MyHandler implements InvocationHandler {
    private Object target;

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

    @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;
    }
}
4. 测试

java

运行

复制代码
public class Test {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();

        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new MyHandler(target)
        );

        proxy.add();
    }
}

输出

plaintext

复制代码
方法前:日志
添加用户
方法后:提交事务

三、CGLIB 动态代理(无接口也能用)

核心类

  • MethodInterceptor
  • Enhancer

示例(关键代码)

java

运行

复制代码
public class CglibInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("前增强");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("后增强");
        return result;
    }
}

// 生成代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new CglibInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.add();

四、常见面试要点

  1. JDK vs CGLIB

    • JDK:接口、快、原生
    • CGLIB:继承、可代理普通类、Spring 常用
  2. 动态代理用途

    • Spring AOP
    • MyBatis Mapper 代理
    • 全局日志、权限校验、事务管理
  3. 为什么 JDK 必须要接口? 因为生成的代理类 已经继承了 Proxy,Java 单继承,只能通过接口扩展。

相关推荐
段一凡-华北理工大学5 分钟前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe14 分钟前
C++——多态
开发语言·c++
心平气和量大福大1 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
莫逸风2 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
从零开始的代码生活_2 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸2 小时前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++
z123456789863 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
GIS阵地3 小时前
QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)
开发语言·前端·c++·qt·qgis
yaoxin5211234 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python
groundhappy4 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python