动态代理和静态代理的区别
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
代理模式是Java开发中常用的设计模式,核心作用是通过代理对象间接访问目标对象,实现功能增强、权限控制、日志打印、事务管理等非业务逻辑的解耦。根据代理类的生成时机和实现方式,分为静态代理和动态代理,二者在开发效率、扩展性、底层原理上存在本质差异。
一、静态代理:编译期硬编码的固定代理
1. 核心定义
静态代理是在代码编译阶段,由开发者手动编写代理类源码,代理类和目标类实现同一个接口、持有目标对象引用,最终和目标类一起编译成class文件。代理逻辑提前写死在代码中,运行时直接调用编译好的代理类。
2. 实现特点
- 手动编码:每个目标类都需要单独编写对应的代理类,代理类与目标类一一绑定
- 编译期生成:代理类.java文件提前编写,javac编译后生成固定的代理类.class
- 接口绑定:必须和目标类实现相同的接口,通过接口调用目标方法
3. 典型优缺点
优点:实现简单、直观,不需要依赖第三方框架,小场景下易调试;
缺点:代码冗余度极高,新增目标类/新增增强逻辑都要修改代理类,扩展性极差,不适合大规模业务开发。
二、动态代理:运行期动态生成的灵活代理
1. 核心定义
动态代理无需手动编写代理类源码,在程序运行阶段通过Java反射机制(JDK动态代理)或字节码生成技术(CGLIB动态代理),动态创建代理类对象并加载到JVM。代理逻辑统一封装,无需针对每个目标类单独开发,实现横切逻辑的复用。
2. 主流实现方案
- JDK动态代理:Java原生支持,基于接口实现,目标类必须实现接口,通过InvocationHandler调用目标方法
- CGLIB动态代理:第三方字节码框架,基于继承实现,无需目标类实现接口,通过生成目标类子类作为代理类
3. 核心特点
无手动代理类源码、运行时动态生成、一套增强逻辑可适配多个目标类、横切功能(日志、事务)可统一封装,彻底解耦业务与非业务代码。
三、静态代理 vs 动态代理:核心维度对比
代理类生成时机 | 编译期(提前编写.java文件,编译成.class) | 运行期(JVM加载时动态生成字节码,无源码文件) |
代码编写方式 | 手动硬编码,代理类与目标类一一对应 | 无需编写代理类,通过反射/字节码自动生成 |
代码复用性 | 极差,增强逻辑分散,无法复用 | 极强,一套增强逻辑适配所有目标类 |
灵活性 | 极低,新增方法/目标类需重写代理类 | 极高,动态适配目标类,无需修改原有代码 |
扩展性 | 差,维护成本高,不适合复杂场景 | 优,支持统一横切扩展,适配大规模项目 |
依赖要求 | 无第三方依赖,纯原生代码 | JDK代理需接口,CGLIB需引入第三方包 |
运行性能 | 略高,无反射开销,直接调用 | 略低,存在反射/字节码生成开销(可忽略) |
适用场景 | 目标类少、逻辑固定、简单业务场景 | 框架开发、AOP切面、事务管理、日志统一处理等复杂场景 |
四、关键总结:一句话分清二者
静态代理是“提前造好的固定工具”,针对性强但通用性差;动态代理是“运行时按需造工具”,通用性极强、扩展性拉满,是Spring AOP等主流框架的核心底层实现。
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
本专栏聚焦Spring全生态体系,从IoC/AOP核心原理入手,覆盖Spring Boot自动配置、事务管理、Web开发等实战内容。拆解循环依赖、动态代理等高频面试难点,助力开发者从入门到精通,打通单体到微服务的技术链路,解决企业级开发痛点,提升架构设计与问题排查能力,成为Java后端进阶的必备技术专栏。