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

一文深入学习Java动态代理-JDK动态代理和CGLIB

在Java中,动态代理是一种运行时动态生成代理对象的技术,属于代理模式的进阶实现。它无需像静态代理那样手动编写代理类,而是通过框架在运行时自动生成代理类字节码,从而简化代理逻辑的实现,提升代码灵活性。

一、代理模式的核心思想

代理模式的核心是:通过代理对象间接访问目标对象,在不修改目标对象代码的前提下,为目标对象的方法添加额外功能(如日志、事务、权限校验等)

  • 目标对象:被代理的原始对象(如业务逻辑类)。
  • 代理对象:持有目标对象的引用,对外提供与目标对象相同的方法,但在方法执行前后可添加增强逻辑。

二、静态代理的局限

静态代理是代理模式的基础实现,需要手动为每个目标类编写代理类(代理类与目标类实现相同接口)。但它存在明显局限:

  • 代理类与目标类强耦合,若接口新增方法,所有代理类都需同步修改,维护成本高。
  • 当目标类数量多且接口方法复杂时,会产生大量重复的代理代码。

例如,若有100个业务类,静态代理需要编写100个对应的代理类,显然不现实。动态代理正是为解决这一问题而生。

三、Java动态代理的两种实现方式

Java中动态代理的主流实现有两种:JDK动态代理(基于接口)和CGLIB动态代理(基于继承)。

1. JDK动态代理(基于接口)

JDK动态代理是Java原生支持的代理方式,核心依赖java.lang.reflect包下的两个类:Proxy(生成代理对象)和InvocationHandler(定义代理逻辑)。

核心要求:目标类必须实现至少一个接口(代理对象会实现相同接口)。

实现步骤:

以“为用户服务类添加日志增强”为例:

  • Step 1:定义接口(目标类需实现)
    接口中声明目标方法(代理对象会实现这些方法)。

    // 用户服务接口
    public interface UserService {void addUser(String name);
    }
    
  • Step 2:实现目标类
    目标类是实际业务逻辑的载体,需实现上述接口。

    // 目标类(被代理的类)
    public class UserServiceImpl implements UserService {@Overridepublic void addUser(String name) {System.out.println("执行核心业务:添加用户 " + name);}
    }
    
  • Step 3:定义代理逻辑(实现InvocationHandler)
    InvocationHandler是一个函数式接口,其中的invoke方法是代理逻辑的核心:当调用代理对象的方法时,会自动触发invoke方法执行。

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;// 代理逻辑处理器
    public class LogInvocationHandler implements InvocationHandler {// 持有目标对象的引用private Object target;public LogInvocationHandler(Object target) {this.target = target;}/*** 代理逻辑核心方法* @param proxy  代理对象(一般不用)* @param method 目标方法(被调用的方法)* @param args   目标方法的参数* @return 目标方法的返回值*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 增强逻辑:方法执行前System.out.println("【日志】方法 " + method.getName() + " 开始执行,参数:" + args[0]);// 调用目标对象的方法(核心业务)Object result = method.invoke(target, args);// 增强逻辑:方法执行后System.out.println("【日志】方法 " + method.getName() + " 执行结束");return result;}
    }
    
  • Step 4:生成代理对象(通过Proxy类)
    使用Proxy.newProxyInstance()方法动态生成代理对象,需要3个参数:

    • 类加载器(与目标类相同);
    • 目标类实现的接口数组;
    • 上述InvocationHandler实例(代理逻辑)。
    import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {// 1. 创建目标对象UserService target = new UserServiceImpl();// 2. 创建代理逻辑处理器(传入目标对象)LogInvocationHandler handler = new LogInvocationHandler(target);// 3. 动态生成代理对象(代理对象实现UserService接口)UserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),  // 类加载器target.getClass().getInterfaces(),   // 目标类实现的接口handler                              // 代理逻辑);// 4. 调用代理对象的方法(会触发invoke方法)proxy.addUser("张三");}
    }
    

执行结果

【日志】方法 addUser 开始执行,参数:张三
执行核心业务:添加用户 张三
【日志】方法 addUser 执行结束
2. CGLIB动态代理(基于继承)

CGLIB(Code Generation Library)是一个第三方字节码生成库,它通过继承目标类生成代理对象(无需目标类实现接口)。核心依赖net.sf.cglib包下的MethodInterceptor接口(定义代理逻辑)和Enhancer类(生成代理对象)。

核心要求:目标类不能是final(否则无法继承),目标方法不能是final(否则无法重写增强)。

实现步骤:

同样以“为用户服务类添加日志增强”为例(目标类无需实现接口):

  • Step 1:引入CGLIB依赖
    若使用Maven,需在pom.xml中添加:

    <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
    </dependency>
    
  • Step 2:定义目标类(无需实现接口)

    // 目标类(被代理的类,无需实现接口)
    public class UserService {public void addUser(String name) {System.out.println("执行核心业务:添加用户 " + name);}
    }
    
  • Step 3:定义代理逻辑(实现MethodInterceptor)
    MethodInterceptor接口中的intercept方法是代理逻辑核心:调用代理对象的方法时,会触发该方法。

    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import java.lang.reflect.Method;// CGLIB代理逻辑处理器
    public class LogMethodInterceptor implements MethodInterceptor {/*** 代理逻辑核心方法* @param obj       代理对象* @param method    目标方法* @param args      目标方法参数* @param proxy     方法代理(用于调用目标方法)* @return 目标方法返回值*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 增强逻辑:方法执行前System.out.println("【日志】方法 " + method.getName() + " 开始执行,参数:" + args[0]);// 调用目标对象的方法(核心业务)Object result = proxy.invokeSuper(obj, args);  // 注意:通过methodProxy调用父类(目标类)方法// 增强逻辑:方法执行后System.out.println("【日志】方法 " + method.getName() + " 执行结束");return result;}
    }
    
  • Step 4:生成代理对象(通过Enhancer类)
    Enhancer是CGLIB的核心类,用于生成代理对象,需指定父类(目标类)和回调(代理逻辑)。

    import net.sf.cglib.proxy.Enhancer;public class Main {public static void main(String[] args) {// 1. 创建增强器Enhancer enhancer = new Enhancer();// 2. 设置父类(目标类,代理类会继承该类)enhancer.setSuperclass(UserService.class);// 3. 设置回调(代理逻辑)enhancer.setCallback(new LogMethodInterceptor());// 4. 生成代理对象(代理对象是UserService的子类)UserService proxy = (UserService) enhancer.create();// 5. 调用代理对象的方法(会触发intercept方法)proxy.addUser("李四");}
    }
    

执行结果

【日志】方法 addUser 开始执行,参数:李四
执行核心业务:添加用户 李四
【日志】方法 addUser 执行结束

四、JDK动态代理 vs CGLIB动态代理

维度JDK动态代理CGLIB动态代理
底层原理基于接口实现(代理类实现目标接口)基于继承实现(代理类继承目标类)
目标类要求必须实现至少一个接口不能是final类,方法不能是final
性能(JDK8+)生成代理对象快,运行时性能略优生成代理对象慢(需生成字节码),运行时性能略差(差异极小)
依赖Java原生支持,无需额外依赖需引入CGLIB库

五、动态代理的典型应用场景

动态代理是许多框架的核心技术,例如:

  • Spring AOP:通过动态代理实现切面逻辑(如事务、日志)与业务逻辑的分离(默认对接口用JDK代理,对类用CGLIB)。
  • RPC框架:通过动态代理生成远程服务的本地代理对象,屏蔽网络通信细节。
  • 权限控制:在方法调用前通过代理校验用户权限。
  • 日志记录:在方法执行前后自动记录日志。

总结

动态代理的核心价值是**“运行时动态生成代理对象,在不侵入目标类的前提下增强方法逻辑”**。JDK动态代理基于接口,适用于目标类有接口的场景;CGLIB基于继承,适用于目标类无接口的场景。两者各有优劣,实际开发中可根据目标类特性选择。

http://www.dtcms.com/a/544862.html

相关文章:

  • 嵌入式开发学习日志42——stm32之SPI工作方式
  • 网站是什么时候出现的淄博市建设局网站首页
  • MATLAB高效算法实战:30倍提速秘籍
  • 开发个网站开票名称是什么开源做网站需要申请账号吗
  • 从PLY到3DTiles:GISBox助力三维数据格式转换全流程
  • 在 PowerPoint 中自动化创建图表:使用 Spire.Presentation for Java 轻松实现数据可视化
  • day02(10.29)——leetcode面试经典150
  • 实战:用Matplotlib将爬取的CSV数据变成直观图表
  • python数据分析项目之:房地产数据可视化分析
  • 银川微信网站开发一块地需要多少钱
  • Unity编辑器扩展入门篇 - Unity Assets菜单
  • html中音乐网站怎么做自助建站系统建的网站做排名吗
  • 【Linux命令】对ps -ef命令的输出的解读
  • 第二届大数据、神经网络与深度学习研讨会(BDNNDL 2025)
  • 2025年免费aippt排行
  • 【大模型】理论基础(1):函数与神经网络
  • 认识主板总结与硬件工程师岗位笔试面试题集
  • Spring Boot Actuator 监控机制解析
  • 建设网站协议范本哈尔滨制作网页公司
  • 文章修改网站旅游管理论文题目选题
  • Rabbitmq扇形队列取消绑定交换机之后任然接收消息问题
  • 网站正在建设中代码哪个软件发视频可以赚钱
  • web网页开发,天气可视化开发,基于Python,FlaskWeb,无数据,数据写死
  • S11e Protocol:重塑品牌资产的 Web3 RWA 基础设施革命
  • 34_AI智能体工具插件之动态注册钉钉待办工具构建企业级任务管理AI助手
  • Java 大视界 -- Java 大数据在智慧文旅旅游线路规划与游客流量均衡调控中的应用实践
  • 33_AI智能体工具插件之钉钉API交互工具封装构建企业级AI应用
  • 数字孪生热力图可视化为何被广泛应用?
  • 国内免费可商用图片素材网站孝感做招聘信息的网站
  • Django在服务端的部署(无废话)