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

Java动态代理详解:小白也能彻底搞懂动态代理!

🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)

🎬精选专栏:数据结构与算法,JavaSE ,苍穹外卖日记,AI学习

前言

在学习 Spring 的时候,你一定听过这样一句话:

Spring AOP 的底层就是动态代理

很多同学第一次看到动态代理时都会懵:

  • 什么是代理?

  • 为什么需要代理?

  • 动态代理和静态代理有什么区别?

  • InvocationHandler 又是什么东西?

  • Spring 为什么离不开动态代理?

别慌。今天我们就用最通俗的方式,把 Java 动态代理讲明白。

看完这篇文章,你不仅能写出动态代理代码,还能理解 Spring AOP 为什么能够在方法执行前后自动增强功能。


一、什么是代理?

在讲动态代理之前,我们先理解什么是代理。

生活中其实到处都是代理。

举个例子:

假设你想买房。

正常流程:

买家 → 房东

但是现实中很多人不会直接找房东,而是找中介:

买家 → 中介 → 房东

中介就是代理。

它帮你完成:

  • 带看房

  • 签合同

  • 收取佣金

但真正卖房的还是房东。


对应到程序中,假设有一个用户服务:

public interface UserService { void login(); }

实现类:

public class UserServiceImpl implements UserService { @Override public void login() { System.out.println("用户登录..."); } }

如果我们想在登录前后增加日志:

记录日志 ↓ 执行登录 ↓ 记录日志

怎么办?

直接修改源代码?

public void login() { System.out.println("记录日志"); System.out.println("用户登录"); System.out.println("记录日志"); }

可以,但不优雅。

因为业务代码和日志代码耦合在一起了。

于是代理模式出现了。


二、什么是静态代理?

静态代理很好理解。

代理类提前写好。

创建代理类

public class UserServiceProxy implements UserService { private UserService userService; public UserServiceProxy(UserService userService) { this.userService = userService; } @Override public void login() { System.out.println("记录日志"); userService.login(); System.out.println("记录日志"); } }

测试:

public class Test { public static void main(String[] args) { UserService target = new UserServiceImpl(); UserService proxy = new UserServiceProxy(target); proxy.login(); } }

输出:

记录日志 用户登录... 记录日志

静态代理的问题

假设系统有:

UserService OrderService ProductService

每个都要写代理类:

UserServiceProxy OrderServiceProxy ProductServiceProxy

项目越大:

代理类越来越多 维护成本越来越高

怎么办?

Java 提供了动态代理


三、什么是动态代理?

你可以理解成:

代理对象不需要程序员手动创建,而是在运行时动态生成。

说白了:

静态代理: 程序员自己写代理类 动态代理: JVM帮你生成代理类

这就是动态代理。


四、动态代理核心组成

JDK动态代理主要有两个核心类:

Proxy

负责生成代理对象。

Proxy.newProxyInstance()

InvocationHandler

负责拦截方法。

invoke()

所有方法调用最终都会来到这里。

你可以理解成:

客户 ↓ 代理对象 ↓ invoke() ↓ 目标对象

五、动态代理工作流程

假设执行:

proxy.login();

整个过程如下:

调用代理对象 ↓ 进入invoke() ↓ 执行前置增强 ↓ 调用真实对象 ↓ 执行后置增强 ↓ 返回结果

流程图:

客户端 ↓ 代理对象 ↓ InvocationHandler ↓ 目标对象

这就是 Spring AOP 的核心思想。


六、JDK动态代理代码实战

第一步:定义接口

public interface UserService { void login(); void register(); }

第二步:实现类

public class UserServiceImpl implements UserService { @Override public void login() { System.out.println("用户登录"); } @Override public void register() { System.out.println("用户注册"); } }

第三步:创建代理处理器

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LogHandler implements InvocationHandler { //目标对象 private Object target; public LogHandler(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; } }

第四步:生成代理对象

import java.lang.reflect.Proxy; 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 LogHandler(target) ); proxy.login(); System.out.println("------------"); proxy.register(); } }

运行结果:

方法执行前记录日志 用户登录 方法执行后记录日志 ------------ 方法执行前记录日志 用户注册 方法执行后记录日志

成功实现了功能增强,并且没有修改业务代码


七、Proxy.newProxyInstance详解

很多同学最怕这一行:

Proxy.newProxyInstance(...)

其实并不复杂。

Proxy.newProxyInstance( classLoader, interfaces, handler )

参数1:类加载器

target.getClass().getClassLoader()

用于加载代理类。

一般直接这么写即可。


参数2:接口数组

target.getClass().getInterfaces()

告诉 JVM:

我要代理哪些接口

参数3:InvocationHandler

new LogHandler(target)

方法增强逻辑写在这里。


八、为什么JDK动态代理必须有接口?

很多面试官喜欢问:

JDK动态代理为什么要求目标对象实现接口?

原因很简单。

JDK生成的代理类本质上:

class ProxyClass implements UserService

代理类通过实现接口完成代理。

如果没有接口:

class UserServiceImpl

JDK就不知道该实现什么。

所以:

JDK动态代理 必须有接口

九、没有接口怎么办?

这时候就轮到 CGLIB 出场了。

原理:

JDK动态代理: 实现接口 CGLIB: 继承目标类

例如:

class UserService

CGLIB生成:

class UserServiceProxy extends UserService

这样即使没有接口也能代理。


Spring AOP 的规则:

有接口 优先JDK动态代理 无接口 使用CGLIB

十、动态代理的底层原理

很多人以为:

Proxy.newProxyInstance()

只是返回一个对象。

其实背后 JVM 做了很多事。

大致流程:

生成字节码 ↓ 生成代理类 ↓ 加载到JVM ↓ 创建对象 ↓ 返回代理实例

本质上:

动态生成一个新的class文件

只不过这些过程 JVM 帮我们完成了。


十一、动态代理的优缺点

优点

1. 解耦

业务代码不需要关心日志。

业务 日志 权限 事务

各自独立。


2. 代码复用

一个代理可以增强多个对象。


3. 扩展方便

增加新功能不用修改源码。

符合:

开闭原则

缺点

1. 增加理解成本

初学者看不懂。


2. 调试困难

调用链变长。


3. 性能略有损耗

因为多了一层代理。

不过现代 JVM 优化后影响非常小。


十二、实际开发中的应用

动态代理在企业项目中非常常见。


Spring AOP

@Before @After @Around

底层就是动态代理。


Spring事务

@Transactional

本质也是代理。

执行流程:

开启事务 ↓ 执行方法 ↓ 提交事务

MyBatis

Mapper接口:

UserMapper

实际上没有实现类。

为什么还能调用?

userMapper.selectById()

因为 MyBatis 底层动态生成了代理对象。


RPC框架

例如:

Dubbo OpenFeign

底层都大量使用动态代理。


十三、扩展

1、什么是动态代理?

运行期间动态生成代理对象,实现方法增强。


2、动态代理有哪些实现方式?

JDK动态代理 CGLIB动态代理

3、JDK动态代理核心接口?

InvocationHandler

4、JDK动态代理为什么必须有接口?

代理类通过实现接口生成。

没有接口无法实现。


5、Spring AOP使用什么代理?

有接口:JDK代理 无接口:CGLIB代理

6、MyBatis为什么接口没有实现类还能调用?

因为底层使用动态代理生成Mapper对象。


总结

动态代理可以说是 Java 框架世界的基石。

很多框架看起来很神奇:

  • Spring AOP

  • Spring事务

  • MyBatis

  • OpenFeign

  • Dubbo

本质上都离不开动态代理。

静态代理是程序员自己写代理类,动态代理是 JVM 帮你生成代理类。

再记住动态代理的核心流程:

调用代理对象 ↓ 进入invoke() ↓ 执行增强逻辑 ↓ 调用目标对象 ↓ 返回结果

当你真正理解之后,Spring AOP、事务、MyBatis 的底层原理也就打开了一半的大门。

http://www.jsqmd.com/news/949540/

相关文章:

  • 2026年黄山市黄金回收白银回收铂金回收门店 TOP5榜单无套路:实体店铺地址电话一览 - 诚金汇钻回收公司
  • 2026年衡阳市黄金回收白银回收铂金回收门店 TOP5榜单无套路:实体店铺地址电话一览 - 诚金汇钻回收公司
  • Typora格式规范检测终极指南:让Markdown写作更专业更高效
  • 【Redis从入门到精通】第54篇:发布订阅实战——实时消息推送、聊天室、事件通知
  • Arduino音乐播放器实战:从PWM原理到嵌入式系统设计
  • 2026年新疆高新技术企业申报时间流程及南北疆差异化补贴细则
  • 告别复杂配置:用快马AI一键生成你的第一个LaTeX学术论文模板
  • 石家庄黄金回收找哪家?这五家正规门店免费上门,久美30年零差评 - 行行星
  • 归并排序(递归代码)
  • 深度测评2026年长沙小程序开发高口碑推荐榜单,你选对了吗?
  • 基于LPJ模型的植被NPP模拟、驱动力分析及其气候变化响应预测
  • 漯河市2026年黄金回收白银回收铂金回收放心选真心推荐 靠谱门店排行 + 联系电话整理 - 中业金奢再生回收中心
  • 如何用OpenMir2快速搭建热血传奇游戏服务器:C完整实战指南
  • 【Redis从入门到精通】第55篇:Redis事务——MULTI/EXEC/DISCARD/WATCH详解
  • VR-Reversal:免费解锁VR视频的终极观看指南,让3D内容在普通设备自由播放!
  • 2026年梅州市口碑首选!黄金回收铂金回收白银回收权威门店 TOP5 附咨询电话 - 信誉隆金银铂奢回收
  • 96110是什么电话?新流派带你了解反诈专线背后的秘密
  • 基于树莓派与OpenCV的实时人脸识别系统:从硬件搭建到算法部署全流程
  • Grok4 API低成本接入实战:绕过付费墙的合规工程路径
  • 软件开发模型——迭代模型
  • # 2026年烟台搬家公司实力排行榜,基于搬家行业的五大权威推荐榜单 - 十大品牌榜
  • 3PEAK思瑞浦 LMV358B-TSR TSSOP8 运算放大器
  • Qwen3.6-27B本地部署262K上下文:软硬件配置全解析
  • 2026国产数据库全景图:按架构、按行业、按能力三维度一表选型
  • 别只画图了!深度挖掘VOSviewer三大视图(网络/覆盖/密度)背后的科研故事与隐藏信息
  • 告别pip install失败:手把手教你搞定Python Click的离线安装(附国内镜像源大全)
  • VOCs检测车监控管理平台解决方案
  • 辽源市2026年黄金回收白银回收铂金回收权威门店 TOP5+正规可靠机构电话与地址汇总 - 中安检金银铂钻回收
  • 成本节省超30%!GPON OLT助力襄阳智慧物流园改造 - 资讯速览
  • 基于ESP32的独立CP/M模拟器:复古计算与现代硬件的完美融合