在这里插入图片描述

在 Java 开发中,动态代理是实现 AOP(面向切面编程)的核心技术,广泛应用于日志记录、事务管理、权限控制等场景。其中,JDK 动态代理和 CGlib 是两种最常用的动态代理实现方式。本文将从原理、区别、使用场景等方面深入解析这两种技术,帮助开发者更好地理解和选择。

一、动态代理的基本概念

动态代理是一种在运行时动态生成代理类的技术,无需手动编写代理类代码。其核心作用是:在不修改目标对象代码的前提下,对目标对象的方法进行增强(如在方法执行前后添加日志、性能监控等逻辑)。

简单来说,动态代理就像给目标对象 “套了一层壳”,所有对目标对象的调用都会先经过这层壳,从而实现增强逻辑的统一管理。

二、JDK 动态代理

1. 原理

JDK 动态代理是 Java 官方提供的代理技术,基于接口和反射机制实现:

  • 要求目标类必须实现一个或多个接口
  • 运行时,JDK 会动态生成一个实现了目标类所有接口的代理类($ProxyXXX)。
  • 代理类通过调用InvocationHandler接口的invoke方法,将增强逻辑与目标方法的执行结合起来。

2. 核心接口:InvocationHandler

public interface InvocationHandler {// proxy:代理对象本身// method:目标方法// args:目标方法的参数Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

代理类的所有方法调用都会被转发到invoke方法,开发者需在该方法中实现增强逻辑。

3. 实现示例

步骤 1:定义目标接口和实现类
// 目标接口
public interface UserDao {void add();
}// 目标类(实现接口)
public class UserDaoImpl implements UserDao {@Overridepublic void add() {System.out.println("执行UserDao的add方法");}
}
步骤 2:实现 InvocationHandler
public class JdkProxyHandler implements InvocationHandler {// 目标对象(被代理的原始对象)private Object target;public JdkProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 增强逻辑:方法执行前System.out.println("JDK代理:方法执行前(日志记录)");// 执行目标方法Object result = method.invoke(target, args);// 增强逻辑:方法执行后System.out.println("JDK代理:方法执行后(日志记录)");return result;}
}
步骤 3:生成代理对象并使用
public class JdkProxyDemo {public static void main(String[] args) {// 目标对象UserDao target = new UserDaoImpl();// 生成代理对象(通过Proxy类的newProxyInstance方法)UserDao proxy = (UserDao) Proxy.newProxyInstance(target.getClass().getClassLoader(), // 类加载器target.getClass().getInterfaces(),  // 目标类实现的接口new JdkProxyHandler(target)         // 增强逻辑处理器);// 调用代理对象的方法(实际会执行增强逻辑+目标方法)proxy.add();}
}
输出结果
JDK代理:方法执行前(日志记录)
执行UserDao的add方法
JDK代理:方法执行后(日志记录)

三、CGlib 动态代理

1. 原理

CGlib(Code Generation Library)是一个第三方字节码生成库,基于继承实现动态代理:

  • 不要求目标类实现接口,通过生成目标类的子类作为代理类。
  • 运行时,CGlib 会动态生成目标类的子类,并重写目标类的非 final 方法。
  • 代理逻辑通过MethodInterceptor接口的intercept方法实现。

2. 核心接口:MethodInterceptor

public interface MethodInterceptor {// obj:代理对象(目标类的子类)// method:目标方法// args:目标方法的参数// proxy:方法代理对象(用于调用目标方法)Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

3. 实现示例

步骤 1:添加 CGlib 依赖(Maven)
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
步骤 2:定义目标类(无需实现接口)
public class UserService {public void update() {System.out.println("执行UserService的update方法");}
}
步骤 3:实现 MethodInterceptor
public class CglibInterceptor implements MethodInterceptor {// 目标对象private Object target;public CglibInterceptor(Object target) {this.target = target;}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 增强逻辑:方法执行前System.out.println("CGlib代理:方法执行前(性能监控)");// 执行目标方法(通过代理对象调用父类方法)Object result = proxy.invokeSuper(obj, args);// 增强逻辑:方法执行后System.out.println("CGlib代理:方法执行后(性能监控结束)");return result;}
}
步骤 4:生成代理对象并使用
public class CglibDemo {public static void main(String[] args) {// 目标对象UserService target = new UserService();// CGlib增强器(用于生成代理类)Enhancer enhancer = new Enhancer();// 设置父类(目标类)enhancer.setSuperclass(UserService.class);// 设置回调(增强逻辑)enhancer.setCallback(new CglibInterceptor(target));// 生成代理对象(目标类的子类)UserService proxy = (UserService) enhancer.create();// 调用代理对象的方法proxy.update();}
}
输出结果
CGlib代理:方法执行前(性能监控)
执行UserService的update方法
CGlib代理:方法执行后(性能监控结束)

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

对比维度JDK 动态代理CGlib 动态代理
底层技术基于接口 + 反射基于继承 + 字节码生成(ASM 库)
目标类要求必须实现接口可无接口(但不能是 final 类 / 方法)
代理类生成实现目标接口的代理类继承目标类的子类
效率反射调用,效率较低(JDK 8+后优化明显)直接调用子类方法,效率较高
灵活性仅能代理接口方法可代理类中所有非 final 方法
依赖JDK 内置,无需额外依赖需要引入 CGlib 库

关键区别总结:

  1. 接口依赖:JDK 动态代理强制要求目标类实现接口,CGlib 无此限制。
  2. 性能:在多次调用场景下,CGlib 效率更高(因避免了反射开销)。
  3. 限制:CGlib 无法代理 final 类或 final 方法(子类无法重写)。

五、Spring 中的选择策略

Spring AOP 默认根据目标类是否实现接口自动选择代理方式:

  • 若目标类实现了接口:默认使用 JDK 动态代理。
  • 若目标类未实现接口:自动切换为 CGlib 代理。

若需强制使用 CGlib(即使目标类有接口),可通过配置开启:

  • XML 配置:<aop:aspectj-autoproxy proxy-target-class="true"/>
  • 注解配置:@EnableAspectJAutoProxy(proxyTargetClass = true)

六、使用场景建议

  1. 优先用 JDK 动态代理

    • 目标类已实现接口。
    • 追求开发便捷性(无需额外依赖)。
    • 方法调用频率不高的场景。
  2. 选择 CGlib

    • 目标类无接口,或需代理非接口方法。
    • 对性能要求高(如高频调用的核心服务)。
    • 可接受引入第三方依赖。

七、总结

JDK 动态代理和 CGlib 是动态代理的两大主流实现,各有优劣:

  • JDK 动态代理基于接口,简单易用,是 Spring 的默认选择。
  • CGlib 基于继承,性能更优,适合无接口或高性能需求的场景。

理解两者的原理和区别,有助于在实际开发中根据场景合理选择,也能更深入地理解 Spring AOP 等框架的底层实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/915776.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915776.shtml
英文地址,请注明出处:http://en.pswp.cn/news/915776.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

变频器带动电机:全方位解析参数变化

在现代工业自动化领域&#xff0c;变频器作为电机调速的核心设备&#xff0c;扮演着至关重要的角色。它能够精准地控制电机的运行状态&#xff0c;通过改变电源频率和电压&#xff0c;实现电机转速、转矩、功率等参数的灵活调整。本文将深入探讨变频器带动电机时&#xff0c;各…

OpenCV 入门知识:图片展示、摄像头捕获、控制鼠标及其 Trackbar(滑动条)生成!

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

Elasticsearch是什么?

Elasticsearch&#xff08;简称ES&#xff09;是一种基于Lucene的分布式搜索引擎&#xff0c;广泛应用于大数据、日志分析、全文搜索等场景。它的核心是提供高效、可扩展的搜索和分析能力。ES 提供了强大的全文搜索、聚合分析、数据可视化等功能&#xff0c;可以用来快速地对海…

(Arxiv-2025)OmniGen2:通向先进多模态生成的探索

OmniGen2&#xff1a;通向先进多模态生成的探索 paper title&#xff1a;OmniGen2: Exploration to Advanced Multimodal Generation paper是BAAI发布在Arxiv 2025的工作 Code:链接 Abstract 在本研究中&#xff0c;我们提出了 OmniGen2&#xff0c;这是一种多功能、开源的生成…

期权到期会对大盘有什么影响?

本文主要介绍期权到期会对大盘有什么影响&#xff1f;期权到期对大盘的影响主要体现在以下几个方面&#xff0c;但整体影响通常有限且短期&#xff0c;具体效果需结合市场环境、期权规模及行权价位置综合判断。期权到期会对大盘有什么影响&#xff1f;1. 市场流动性波动到期日效…

【LeetCode刷题指南】--随机链表的复制

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言&#xff1a;生活是默默的坚持&#xff0c;毅力是永久的…

系统学习算法:专题十四 链表

前提知识&#xff1a;1.画图&#xff0c;数据结构相关的题&#xff0c;画图必不可少&#xff0c;只要能画出来&#xff0c;那么后面的代码就很容易能写出来&#xff0c;因为将抽象的数据结构转换为直观的图画2.引入虚拟头结点&#xff0c;也叫哨兵位&#xff0c;能够避免考虑很…

零基础学后端-PHP语言(第一期-PHP环境配置)

从本期开始&#xff0c;我们学习PHP&#xff0c;但是我们要先配置PHP环境 PHP官网链接&#xff1a;PHP For Windows: Binaries and sources Releases 我们可以看到有以下资源 可以看到有很多php的版本&#xff0c;有Non Thread Safe和Thread Safe&#xff0c;还有zip&#xf…

C++ primer知识点总结

《C Primer》系统学习指南&#xff1a;从C到C的平滑过渡根据你提供的《C Primer》目录和你的需求&#xff08;C语言背景转C&#xff0c;侧重网络编程&#xff09;&#xff0c;我将为你制定一个全面的学习计划&#xff0c;包含知识点详解、C/C对比、实战案例和分阶段项目练习。第…

异构融合 4A:重构高性能计算与复杂场景分析的安全与效率边界

当全球数据量以每两年翻一番的速度爆炸式增长&#xff0c;高性能计算&#xff08;HPC&#xff09;与复杂场景分析正成为破解气候预测、基因测序、金融风控等世界级难题的关键引擎。但异构计算环境的碎片化、多系统协同的复杂性、数据流动的安全风险&#xff0c;正在形成制约行业…

【华为机试】240. 搜索二维矩阵 II

文章目录240. 搜索二维矩阵 II描述示例 1示例 2提示解题思路核心分析问题转化算法实现方法1&#xff1a;右上角开始搜索&#xff08;推荐&#xff09;方法2&#xff1a;逐行二分查找方法3&#xff1a;分治法方法4&#xff1a;左下角开始搜索复杂度分析核心要点数学证明右上角搜…

疯狂星期四文案网第16天运营日记

网站运营第16天&#xff0c;点击观站&#xff1a; 疯狂星期四 crazy-thursday.com 全网最全的疯狂星期四文案网站 运营报告 昨日访问量 昨日30多ip, 今天也差不多&#xff0c;同步上周下降了一些&#xff0c;感觉明天疯狂星期四要少很多了&#xff0c;记得上周四700多ip&…

Linux系统基础入门与配置指南

Linux基本概述与配置 一、我们为什么使用Linux&#xff08;Linux的优点&#xff09;开源与自由 免费&#xff1a; 无需支付许可费用&#xff0c;任何人都可以自由下载、安装和使用。源代码开放&#xff1a; 任何人都可以查看、修改和分发源代码。这带来了极高的透明度、安全性和…

如何删除VSCode Marketplace中的publisher

网页上并没有提供删除的按钮&#xff0c;需要通过命令的形式删除。 vsce delete-publisher [要删除的名字]# 键入token # y 确认这里的token是之前在Azure DevOps中创建的token&#xff0c;忘了的话可以重建一个 刷新网页看一下 成功删除了。

Windows安装git教程(图文版)

Git 是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;特别是在软件开发中。它使得多个开发者可以在不同的机器上并行工作&#xff0c;然后将他们的改动合并在一起。是在开发过程中&#xff0c;经常会用到的一个工具。本章教程&#xff0c;主要介绍Windows上…

Remote Framebuffer Protocol (RFB) 详解

RFC 6143 规范文档&#xff1a;The Remote Framebuffer Protocol 文章目录1. 引言2. 初始连接流程2.1 TCP连接建立2.2 协议版本协商2.3 安全握手3. 显示协议机制3.1 核心概念3.2 像素格式4. 输入协议4.1 键盘事件(KeyEvent)4.2 鼠标事件(PointerEvent)5. 协议消息详解5.1 握手消…

从 DeepSeek-V3 到 Kimi K2:八种现代大语言模型架构设计

编译&#xff1a;青稞社区Kimi 原文&#xff1a;https://magazine.sebastianraschka.com/p/the-big-llm-architecture-comparison 首发&#xff1a;https://mp.weixin.qq.com/s/lSM2jk1UxJVz1WllWYQ4aQ 自原始 GPT 架构开发以来已经过去了七年。乍一看&#xff0c;从 2019 年的…

linux驱动开发笔记--GPIO驱动开发

目录 前言 一、设备树配置 二、驱动编写 三、用户空间测试 总结 前言 开发平台&#xff1a;全志A133&#xff0c;开发环境&#xff1a;linux4.9andrio10&#xff0c;开发板&#xff1a;HelperBoard A133_V2.5。 一、设备树配置 打开板级设备树配置文件&#xff0c;路径&a…

腾讯iOA:企业软件合规与安全的免费守护者

人们眼中的天才之所以卓越非凡&#xff0c;并非天资超人一等而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。———— 马尔科姆格拉德威尔 目录 一、为什么要使用腾讯iOA&#xff1f; 二、中小企业软件合规痛点 三、腾讯iOA解决方案 3.1 核心技…

C#定时任务实战指南:从基础Timer到Hangfire高级应用

高效管理后台作业&#xff0c;让定时任务成为应用的可靠引擎 在C#应用开发中&#xff0c;定时任务是实现数据同步、报表生成、系统维护等后台作业的核心技术。本文将深入探讨C#生态中主流的定时任务解决方案&#xff0c;从基础的内置Timer到强大的Quartz.NET和Hangfire框架&…