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

动态代理常用的两种方式?

口语化回答

好的,面试官,动态常见的两种,一种是 jdk 动态代理,一种是 cglib 动态代理,两者的最主要区别是 jdk 动态代理主要是依赖于接口创建代理对象,cglib 是通过生成子类的方式,不需要接口,两种经常会在一起配合,假设类没有接口的时候,就可以通过 cglib 来弥补不足。从性能上来看,因为 jdk 使用反射机制,他的性能,相比 cglib 稍有逊色。cglib 会更占用内存一些。两者都可以满足各种需求,按照有没有接口的原则进行选择。

题目解析

常考题,两种方式非常清晰,大家要记住的是两种所适应的场景,有没有接口的一个区别,这道题后面,经常就会引入出来,spring 用的是什么。

面试得分点

jdk 动态代理,cglib,有无接口,子类

题目详细答案

动态代理常用的两种方式是基于接口的动态代理(JDK 动态代理)和基于类的动态代理(CGLIB 动态代理)。

JDK 动态代理

JDK 动态代理是 Java 标准库提供的一种动态代理机制,它依赖于接口来创建代理对象。JDK 动态代理通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。当你有一个接口并希望为该接口的实现类创建代理时,可以使用 JDK 动态代理。

CGLIB 动态代理

CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它通过生成子类的方式来为目标类创建代理对象。CGLIB 动态代理不需要接口,可以直接代理类。当你没有接口,只有具体类时,可以使用 CGLIB 动态代理。

比较

依赖性

JDK 动态代理依赖于接口,如果没有接口就无法使用。

CGLIB 动态代理可以直接代理类,不需要接口。

性能

JDK 动态代理由于需要通过反射调用方法,性能可能会有所影响。

CGLIB 动态代理通过生成字节码来创建代理类,性能通常比 JDK 动态代理更高,但生成字节码的过程会稍微多占用一些内存。

使用场景

JDK 动态代理适用于有接口的情况,适用于大多数常见的业务场景。

CGLIB 动态代理适用于没有接口的情况,适用于需要代理大量具体类的场景。

动态代理两种实现方式的通俗解释

面试官您好,关于JDK动态代理和CGLIB动态代理的区别,我用一个生活中的例子来简单说明:

核心区别(用租房中介类比)

  1. JDK动态代理 - 像"正规房屋中介"
    • 必须通过租房平台(接口)才能代理
    • 租客只能通过平台联系房东(必须实现接口)
    • 流程规范但灵活性较低
  1. CGLIB动态代理 - 像"熟人介绍的二房东"
    • 直接和房东打交道(不需要接口)
    • 可以改造房屋(增强原有类方法)
    • 更灵活但需要更多手续(生成子类)

具体差异对比

对比项

JDK动态代理

CGLIB动态代理

代理原理

实现接口

继承目标类生成子类

接口要求

必须实现至少一个接口

不需要接口

性能

反射调用稍慢

直接方法调用更快

内存占用

较小

较大(需要生成子类字节码)

适用场景

Spring默认对接口的代理

Spring对普通类的代理

限制

无法代理无接口类

无法代理final类/方法

实际项目中的选择

在我们项目中:

  1. 如果服务类有接口定义,Spring默认用JDK代理(如Service层接口)
public interface UserService {void addUser();
}@Service
public class UserServiceImpl implements UserService {...}
  1. 如果没有接口(如Controller),Spring自动切换CGLIB
@Controller  // 没有实现接口
public class UserController {...}

性能优化的经验

  1. JDK代理优化
    • 减少反射调用(如缓存Method对象)
    • 适合代理方法较少的接口
  1. CGLIB优化
    • 使用Spring Boot 2.x+默认CGLIB
    • 避免代理final方法
    • 大项目要监控PermGen/Metaspace

Spring中的特殊处理

Spring其实很智能:

  • 如果类实现了接口,优先用JDK代理
  • 如果没有接口,自动用CGLIB
  • 可以通过配置强制使用CGLIB:
@EnableAspectJAutoProxy(proxyTargetClass = true)

常见误区提醒

  1. 不是CGLIB一定比JDK快
    • 简单场景差异不大
    • CGLIB初始化成本更高
  1. 代理嵌套问题
@Transactional
@Cacheable
public void foo() {}  // 两种代理可能产生顺序问题
  1. this调用失效
public void bar() {this.foo(); // 不走代理!
}

http://www.lryc.cn/news/611611.html

相关文章:

  • OA系统详解:有哪些功能、主流产品怎么选?
  • 自己本地搭建的服务器怎么接公网?公网IP直连服务器方法,和只有内网IP直接映射到互联网
  • 深度解析:AI如何重塑供应链?从被动响应到预测性防御的三大核心实践
  • 希尔排序:高效插入排序的进阶之道
  • 【JS-7-ajax】AJAX技术:现代Web开发的异步通信核心
  • 【Java String】类深度解析:从原理到高效使用技巧
  • 生成网站sitemap.xml地图教程
  • 从代码学习LLM - llama3 PyTorch版
  • GitHub Spark公共预览版上线
  • 利用OJ判题的多语言优雅解耦方法深入体会模板方法模式、策略模式、工厂模式的妙用
  • 本地服务器端部署基于大模型的通用OCR项目——dots.ocr
  • 达梦数据库日常运维命令
  • cdn是什么
  • 【C++】unordered系列容器使用及封装
  • 生成式 AI 重塑自动驾驶仿真:4D 场景生成技术的突破与实践
  • QT----不同线程中信号发送了槽函数没反应QObject::connect: Cannot queue arguments of typeXXX
  • SG105 Pro 网管交换机的3种VLAN配置
  • java实现生成自定义二维码
  • 软考信息安全工程师11月备考
  • Ragflow介绍与安装
  • 考研408_数据结构笔记(第四章 串)
  • Spearman 相关系数与 Pearson 相关系数的区别
  • Java 工具类的“活化石”:Apache Commons 核心用法、性能陷阱与现代替代方案
  • 湖南14个市州分流线得分率对比
  • 【科研绘图系列】R语言绘制瀑布图
  • RNN梯度爆炸/消失的杀手锏——LSTM与GRU
  • 自学嵌入式 day45 ARM体系架构
  • 异世界历险之数据结构世界(非递归快排,归并排序(递归,非递归))
  • Leetcode题解:739每日温度,用单调栈解决问题!
  • 分布式存储 Ceph 的演进经验 · SOSP 2019