Java静态代理、动态代理(JDK代理、CGLIB代理)常见面试题

2023-11-09

小结:

静态代理不灵活,静态代理类似模板方法设计模式。

动态代理灵活、方便。每个框架都会使用到,例如,spring中的AOP。默认为JDK实现方式,也可选择CGLIB实现方式。

JDK动态代理只能代理实现接口的类或者直接代理接口。限制:必须要有接口。思考:Spring中AOP是如何实现的?(改天会作为一个专题研究一下)

CGLIB动态代理即可代理接口也可代理类。

JDK直接代理类会出现java.lang.IllegalArgumentException: xxx is not an interface异常

常见面试题

1、动态代理是什么?应用场景?

动态代理:在运行时,创建目标类,可以调用和扩展目标类的方法。

Java 中实现动态的方式:

  • JDK 中的动态代理

  • Java类库 CGLib

应用场景:

  • 统计每个 api 的请求耗时

  • 统一的日志输出

  • 校验被调用的 api 是否已经登录和权限鉴定

  • Spring的 AOP 功能模块就是采用动态代理的机制来实现切面编程

2、静态代理和动态代理你怎么看的?有什么区别?

  1. 灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的!

  2. JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

3、动态代理中JDK和CGLIB的区别是什么?

  1. JDK 动态代理只能只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理接口还可以代理未实现任何接口的类 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。

  2. 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。

静态代理

静态代理中,我们对目标对象的每个方法的增强都是手动完成的(*后面会具体演示代码),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类*)。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

上面我们是从实现和应用角度来说的静态代理,从 JVM 层面来说, 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。

静态代理实现步骤:

  1. 定义一个接口及其实现类;

  2. 创建一个代理类同样实现这个接口

  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

代码省略

动态代理

JDK动态代理

在 Java 动态代理机制中 InvocationHandler 接口和 Proxy 类是核心。

Proxy 类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象。

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        ......
    }Copy to clipboardErrorCopied

这个方法一共有 3 个参数:

  1. loader :类加载器,用于加载代理对象。

  2. interfaces : 被代理类实现的一些接口;

  3. h : 实现了 InvocationHandler 接口的对象;

要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

JDK动态代理实现步骤:

  1. 定义一个接口及其实现类;

  2. 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;

  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 方法创建代理对象;

代码省略

CGLIB动态代理

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。

为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心。

你需要自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法。

public interface MethodInterceptor
extends Callback{
    // 拦截被代理类中的方法
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
}
Copy to clipboardErrorCopied
  1. obj :被代理的对象(需要增强的对象)

  2. method :被拦截的方法(需要增强的方法)

  3. args :方法入参

  4. methodProxy :用于调用原始方法

你可以通过 Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。

CGLIB 动态代理类使用步骤

  1. 定义一个类;

  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;

  3. 通过 Enhancer 类的 create()创建代理类;

依赖

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>
​

代码省略

代码GIT:https://gitee.com/naimaohome/talk_about_fage

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java静态代理、动态代理(JDK代理、CGLIB代理)常见面试题 的相关文章

  • 在 Tomcat 上部署 Java Web 项目,无需 WAR 或 EAR

    我有一个 Java Web 项目 Struts Spring 在我的本地主机上完美运行 我必须将其部署在我的网站上 但虚拟主机提供的 Tomcat Manager 界面显示 由于安全原因 它无法上传 WAR 文件 当联系技术支持时 我被告知
  • Java中定义类型后同时初始化多个变量?

    这里需要一些语法方面的帮助 我正在尝试在定义类型后重新初始化多个变量 例如 int bonus sales x y 50 这工作正常 但是我想稍后在程序中将不同的值放入其中一些变量中 但我收到语法错误 bonus 25 x 38 sales
  • JBoss AS 5 中的共享库应该放在哪里?

    我是 Jboss 新手 但我有多个 Web 应用程序 每个应用程序都使用 spring hibernate 和其他开源库和 portlet 所以基本上现在每个 war 文件都包含这些 jar 文件 如何将这些 jar 移动到一个公共位置 以
  • 在 Android 中绘制一条带有弯曲边缘的线

    I am using canvas drawLine to draw some line in android but the lines are too sharp but i need a curved edges 这里的 1 是我所拥
  • 如何在Gradle中支持多种语言(Java和Scala)的多个项目?

    我正在尝试将过时的 Ant 构建转换为 Gradle 该项目包含约50个Java子项目和10个Scala子项目 Java 项目仅包含 Java Scala 项目仅包含 Scala 每个项目都是由 Java 和 Scala 构建的 这大大减慢
  • 用于防止滥用的 Servlet 过滤器? (DoS、垃圾邮件等)

    我正在寻找一个 Servlet 过滤器库 它可以帮助我保护我们的 Web 服务免受未经授权的使用和 DDoS 攻击 我们的网络服务有 授权客户 因此理想情况下 过滤器将帮助检测未经授权或行为不当的客户 或检测使用同一帐户的多个人 此外 我们
  • 中间件 API 的最佳实践是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我们正在开发一个中间件 SDK 采用 C 和 Java 语言 供游戏开发人员 动画软件开发人员 阿凡达开
  • 如何将txt文件添加到你的android项目中? [复制]

    这个问题在这里已经有答案了 我的Android studio版本是1 5 1 显然这个 never 版本没有 txt 文件的 asset 文件夹 您打算如何将这些文件包含到您的项目中 以及如何进一步使用您内部的应用程序 谢谢你的建议 Pro
  • 在多模块项目中访问绑定适配器

    我有一个多模块项目 其中应用程序模块包含我的绑定适配器 而我的功能模块取决于我的应用程序模块 因为它是动态功能模块 应用程序 包含绑定适配器 gt 动态功能模块 存在布局的地方 我在所有模块中启用了数据绑定和 kapt 我无法成功构建应用程
  • NoSuchMethodError:将 Firebase 与应用程序引擎应用程序集成时

    我试图将 firebase 实时数据库与谷歌应用程序引擎应用程序集成 我在调用时收到此错误 gt DatabaseReference ref FirebaseDatabase gt getInstance gt getReference t
  • 删除 ArrayList 对象问题

    我在处理作业时遇到从 ArrayList 中删除对象的问题 如果我使用 正常 for 循环 它的工作原理如下 public void returnBook String isbn for int i 0 i lt booksBorrowed
  • 如何列出所有可用的 LookAndFeel 主题?

    如何列出所有可用的 LookAndFeel 主题 我想在 JComboBox 中显示以供用户选择 这真的很简单 public static UIManager LookAndFeelInfo getInstalledLookAndFeels
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • 如何将任务添加到 gradle 中的主要“构建”任务

    当我尝试使用以下代码将任务添加到主构建任务时 rootProject tasks getByName build dependsOn mytask 当我跑步时它抱怨gradle w build输出 Where Build file line
  • 如何使用maven创建基于spring的可执行jar?

    我有一个基于 Maven 的 Spring WS 客户端项目 我想将其打包为单个 jar 在eclipse中 一切运行正常 当我尝试将其打包为可执行 jar 时 我收到 ClassNotFound 异常 因为 Spring jar 未包含在
  • BoneCP 和 Derby - 如何正确关闭

    I have BoneCP CONNECTION POOL CONNECTION POOL getConfig setJdbcUrl jdbc derby database shutdown true Connection connecti
  • Java中的媒体播放器库[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在评估用于在 Java 中播放音频 视频的库 它不需要 100 Java Java 与本机库的绑定
  • C/C++ 通过 Android NDK 在 JNI 中看不到 Java 方法

    我正在尝试从使用 NDK 构建的 C 类文件调用 Java 方法 它不断抛出常见的 未找到非静态方法 错误并导致整个 Android 应用程序崩溃 下面的代码片段 有些东西可能不需要 但我按原样保留它们 因为焦点 问题在于refreshJN
  • Java:基于 Web 的应用程序中的单例类实例

    我在 Web Application 中有这个 Singleton 类 public class MyDAO private static MyDAO instance private MyDAO public static MyDAO g
  • java中的回调是什么[重复]

    这个问题在这里已经有答案了 可能的重复 什么是回调函数 https stackoverflow com questions 824234 what is a callback function 我已经阅读了回调的维基百科定义 但我仍然没有明

随机推荐

  • Vue ly-tab组件使用

    Vue ly tab组件的使用 目录 Vue ly tab组件的使用 安装 引入 使用 安装 这里使用指定版本安装 如果安装其他版本使用方法可能不一致 npm install ly tab 2 1 2 S 或者 cnpm install l
  • 深入理解采样定理 + Matlab 仿真 Sa 函数的采样与恢复

    建议配合国宝老师的视频食用 信号与线性系统分析 吴大正 郭宝龙 文章目录 1 采样的说明 1 为什么要取样 2 什么是取样 2 采样定理 1 为什么要有奈奎斯特频率 2 什么是采样定理 3 信号的恢复 4 Matlab的Sa函数取样仿真 1
  • nginx通过四层代理实现端口转发

    公司原有的测试数据库在主机192 168 10 5上边 现在数据库转移到了192 168 10 4上 为了不让各个地方都需要更改地址 现在需要一个四层代理工具 将原来请求到192 168 10 5的3306端口转发到192 168 10 4
  • ChatGPT数据泄露,技术细节公布

    事件发生后 OpenAI 临时关闭了 ChatGPT 服务以调查问题 后续 Open AI 的首席执行官 Sam Altman 也亲自发了推文 承认他们确实遭遇了重大问题 不过当时并没有公布问题的细节 只表示是一个开源库的错误导致的 由于一
  • 支持WIN7的VSCode版本

    我有台13年底买的电脑 装的WIN7 使用时发现 最新的VSCode已经不支持WIN7 目前VSCode官网上写的最低支持WIN8 经过确认 最后支持WIN7的版本是1 70 3 不论32位还是64位 都是这个版本
  • easyui 下拉框联动

    supplierCode combobox onChange function n o var supplierCodes n join ajax type post url pageContext request contextPath
  • 前端代码 录音样式 类似微信发送语音

    先来上图 wxml代码 不是小程序的就换成div
  • Python: 基于DearPyGUI的环境变量查看器

    文章目录 1 目的 2 效果 3 实现思路 获取环境变量 分隔环境变量取值 界面显示 4 代码实现 1 目的 无论是 Windows 还是 Linux 下 编辑环境变量总是绕不开的一个基本功 也许你已经熟练使用 vim 来查询和就地替换 P
  • npm下载依赖报错 Invalid dependency type requested: alias

    报这个是alias需要高版本的npm 查看一下npm版本 npm version alias这个好像得是6 9 0版本以上 我使用的是nvm管理node版本 我切换到12版本就可以了 成功安装 在此记录一下踩坑
  • 强化学习的模型

    文章目录 前言 一 强化学习是什么 二 基本模型 1 基本框架 2 学习过程 三 马尔科夫决策过程 Markov Decision Process MDP 1 马尔科夫性质 2 MDP的基本组成部分 3 MDP的基本流程 四 基于模型和免模
  • Tensorflow激活函数--tf.nn.dropout

    前言 激活函数 Activation Function 运行时激活神经网络中某一部分神经元 将激活信息向后传入下一层的神经网络 神经网络的数学基础是处处可微的 所以选取激活函数要保证数据输入与输出也是可微的 激励函数的作用 如果不使用激活函
  • 基于ARIMA算法的时间序列数据预测——matlab实现

    基于ARIMA算法的时间序列数据预测 matlab实现 时间序列分析是一种重要的数据分析方法 它可以对时间序列数据进行统计和预测 ARIMA Autoregressive Integrated Moving Average 是一种常用的时间
  • Spring boot ,dubbo整合异常

    Caused by java lang IllegalArgumentException java lang ClassCastException com guooo boot acc serv impl HelloDubboService
  • 5.39 综合案例2.0 - STM32蓝牙遥控小车2(语音控制)

    综合案例2 0 蓝牙遥控小车1 语音控制 成品展示 案例说明 器件说明 小车连线 小车源码 语音模块遥控 语音遥控连线 模块使用说明 1 MLT BT05 4 0 蓝牙模块 2 ASRPRO 2m模块 下载代码连线 模块编程说明 成品展示
  • css设置内外边框距离

    margin属性可以有一到四个值 p gt margin 25px 50px 75px 100px 上边距为25px 右边距为50px 下边距为75px 左边距为100px margin 25px 50px 75px 上边距为25px 左右
  • Ubuntu20.04 安装 Tomcat 9.0.34

    最近开始使用 Ubuntu 在上面安装 Tomcat了 记录一下 具体步骤和直接在 CentOS 上面的差不多 一 解压安装包 tar zxvf apache tomcat 9 0 34 tar gz 二 修改目录所有权 用ll命令查询 修
  • PAT——团体程序设计天梯赛-练习集(5分题集)Python 3

    该博客记录我参加天梯赛 1 Hello World print Hello World 2 计算摄氏温度 print fahr 100 celsius format int 5 100 32 9 3 计算指数 n int input pri
  • Webservice接口数据抽取_kettel<一>

    在进行ETl数据抽取的时 有时会遇到Webservice接口服务的情况 这里对kettel工具和java脚本两种抽取方式来简单的介绍一下 由于篇幅较长 我分四篇来介绍 下一篇地址 Webservice接口数据抽取 kettel lt 二 g
  • xml 入门 shema_01

    shema基础 shema的使用 shema的属性和语法 相应的源码 1 shema的格式
  • Java静态代理、动态代理(JDK代理、CGLIB代理)常见面试题

    小结 静态代理不灵活 静态代理类似模板方法设计模式 动态代理灵活 方便 每个框架都会使用到 例如 spring中的AOP 默认为JDK实现方式 也可选择CGLIB实现方式 JDK动态代理只能代理实现接口的类或者直接代理接口 限制 必须要有接