Java反射机制,动态代理,hook以及在Retrofit源码中的应用

news2025/6/18 7:48:15

1.反射的基础知识:
Java的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。
反射的基本操作:
获取类对象

获取一个类的 Class 对象有多种方法:

1.1.1使用 Class.forName(String className) 方法,需要传入类的全限定名,会返回该类的 Class 对象。

1.1.2使用类名.class,例如 String.class。

1.1.3使用对象.getClass() 方法,返回对象所属的类的 Class 对象。
获取类的属性

1.2使用 Class 类的 getField(String name) 方法可以获取类的指定公有属性;使用 getDeclaredField(String name) 方法可以获取类的指定属性(无论是否公有)。

1.3获取类的方法

使用 Class 类的 getMethod(String name, Class… parameterTypes) 方法可以获取类的指定公有方法;使用 getDeclaredMethod(String name, Class… parameterTypes) 方法可以获取类的指定方法(无论是否公有)。

1.4获取类的构造函数

使用 Class 类的 getConstructor(Class… parameterTypes) 方法可以获取类的指定公有构造函数;使用 getDeclaredConstructor(Class… parameterTypes) 方法可以获取类的指定构造函数(无论是否公有)。

1.5动态调用方法

通过反射可以动态调用类的方法,例如:

Class clazz = Class.forName(“com.example.MyClass”);
Object obj = clazz.newInstance();
Method method = clazz.getMethod(“myMethod”, String.class);
method.invoke(obj, “parameter”);
上述代码中,我们先获取 MyClass 的 Class 对象,然后创建 MyClass 的一个实例,接着获取 myMethod 方法的 Method 对象,最后使用 invoke 方法调用 myMethod 方法并传入参数。
2.Retrofit源码
在这里插入图片描述
讲上图之前你要本身会使用Retrofit,我们知道Retrofit 的接口是统一集成在一个接口文件中的,所以上图中的service参数就是
类似下图的接口类
在这里插入图片描述
动态代理主要就是利用Proxy.newProxyInstance方法生成代理类,其必须实现InvocationHandler invoke方法,逻辑是如果接口中的方法,记住是所有方法,这也是和使用接口继承去实现的区别,接口中定义的方法统一操作,是动态代理 接口类的一大特征,如果方法是object的方法就直接invoke传入当前对象和参数,如果不是接着往下走,判断当前平台是java,android,还是linux的,如果是系统默认的方法就invoke系统默认的方法,否则用loadServiceMethod来invoke,然后我们看一下下图的loadServiceMethod方法,最后调用了ServiceMethod.parseAnnotations
在这里插入图片描述
然后是HttpServiceMethod.parseAnnotations
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
经过上图的几次跳转后,下图红色箭头的就是最后的CallAdapter接口承接的对象即来自于 callAdapterFactories
在这里插入图片描述
由下图我们找到了是platform.createDefaultCallAdapterFactories产生的
在这里插入图片描述
那我们平台是android 就是android24了,CompletableFutureCallAdapterFactory
和 DefaultCallAdapterFactory
在这里插入图片描述
然后就是代理的实质代码了call.enqueue
在这里插入图片描述
最后会在build里面execute,完成整个流程,代理执行完毕。
在这里插入图片描述
提一句,从下图可以看出来Proxy.newProxyInstance动态代理里面的实现用到了反射。
在这里插入图片描述
3.关于Hook的我做了一个demo,英文翻译过来是钩子,用一个成语表达就是偷梁换柱。用kotlin实现的,比起java会有点不一样的:
看下图,先说要干什么,hook 一下 view的setOnClicklistener的View.OnclickListener。那怎么做呢,因为OnclickListener是接口,可以用动态代理生成,比继承重写接口方便一些。可能你还会有疑问那我直接用一个View.OnclickListener继承类来set进行不就行了,我要说的是这个测试用例只是为了方便描述,这是这个接口有set ,对外是开放的,你可以按你想的那样弄,假如它是不对外开放的呢,hook是不是就有意义了,好了,开始做吧。

在这里插入图片描述
首先我们先看一下view.setOnClickListener方法里面的情况。下图中我们要hook的对象被getListenerInfo()所持有,
在这里插入图片描述
那就看看getListenerInfo()返回的对象是
在这里插入图片描述
是view的一个属性mListenerInfo
在这里插入图片描述
ListenerInfo是View的一个静态内部类,而它的属性mOnClickListener正是我们要找的hook对象了。
在这里插入图片描述
那思路就是利用反射来拿到mListenerInfo对象,拿到它的属性mOnClickListener并替换成 我们动态代理生成的接口。需要注意的是args,kotlin是需要加的。查了查好像说是数组展开,没理解,知道的可以评论区评论。

在这里插入图片描述
然后我们回过头来看反射机制是 基础,动态代理里面也是用反射来实现的,动态代理对类里面的所有方法统一动态加入操作代码,java使用更多是对接口的,是生成了你想往里面塞的代码,hook把hook对象勾出来,换成自己想塞进去的,是一种手法。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32CubeMX安装教程

0.前言 安装步骤: 参考:【STM32】STM32 CubeMx使用教程一--安装教程_Z小旋的博客-CSDN博客 JRE(Java Runtime Environment):Java运行环境STM32CubeMXHAL库:STM32 HAL固件库 1. 安装Java 官网:https://www.java.co…

DNS部署与安全详解(下)

文章目录 前言一、指定区域解析配置二、DNS服务器对外名称显示配置三、转发器使用配置四、配置辅助(备份)服务器五、如何让虚拟机可以真实上网六、为DNS服务器配置别名 前言 上一篇博客我们已经在Windows server2003的虚拟机上下载了DNS软件,…

IDEA 实用小技巧(Scratch files(临时文件))

当你在使用IDEA编写项目代码的时候,是否遇到过如下一些情况? 1. 与别人沟通,需要简写某个功能的伪代码 2. 想记录一些json格式的数据,并且能格式化,即JSON文档功能 3. 想记录一些其他语言例如HTML,CSS&a…

SAP 批量CC11 创建物料版本(RFC:REVISION_LEVEL_INSERT)

REVISION_LEVEL_INSERT FLG_API ‘X’ 就不弹框 不直接报message 需要commit work ,里面有句代码 perform db_insert on commit 输入输出参数如下 输入: 输出: COMMIT 后再看MM03

java实现文件的下载

系统日志的获取不可能每次都登录服务器,所以在页面上能够下载系统运行的日志是必须的 如何来实现日志的下载,这样的一个功能 前端我们用到的是window.open(...)这样可以发送一个get请求到后台 后台接收到get请求之后,如何实现对文件的下载 R…

mac arm 通过brew搭建 php+nginx+mysql+xdebug

1.安装nginx brew install nginx //安装brew services start nginx //启动2.安装php brew install php7.4 //安装export PATH"/opt/homebrew/opt/php7.4/bin:$PATH" //加入环境变量 export PATH"/opt/homebrew/opt/php7.4/sbin:$PATH"brew serv…

EXPLAIN使用分析

系列文章目录 文章目录 系列文章目录一、type说明二、MySQL中使用Show Profile1.查看当前profiling配置2.在会话级别修改profiling配置3.查看profile记录4.要深入查看某条查询执行时间的分布 一、type说明 我们只需要注意一个最重要的type 的信息很明显的提现是否用到索引&…

matplotlib 设置legend的位置在轴最上方,长度与图的长度相同

import matplotlib.pyplot as plt import numpy as npx1 np.linspace(0, 10, 50) x2 [6,4,3]ax plt.subplot() ax.plot(x1, label"test1") ax.plot(x2, label"test2") # 设置图例的位置 # 将左下角放置在【0, 1.02】位置处,横为1&#xff0c…

MySQL——Mysql安装教程- Windows

一、Mysql安装 1、下载mysql安装包 下载链接: 链接: https://pan.baidu.com/s/1rFpMqOCApiQQEwYSs9XSmg https://pan.baidu.com/s/1rFpMqOCApiQQEwYSs9XSmg 提取码:zt88 2、 安装 1)选择电脑磁盘空闲的路径: 2&…

解决error: incompatible type for argument 1 of ‘************’报错

运行程序时出现以下错误: 问题分析:但凡出现error: incompatible type for argument 1 of ‘函数名’几乎都是该函数的参数类型不匹配导致的;所以检查并纠正函数参数类型即可

JUC线程池的实战问题 - 线程池参数应该如何配置?

Oracle 官方并没有给出线程池 corePoolSize 的具体参考值,因为这个值的大小应该根据实际业务场景和系统资源情况来进行优化调整。不同的业务场景和系统资源状况可能需要不同的 corePoolSize 设置。 在《Java并发编程实战》一书中,作者 Brian Goetz 等人…

试卷擦除答案的工具,几个步骤轻松搞定

在学生的学习生活中,考试是必不可少的一部分。然而,有时候我们在做完试卷后发现自己填错了答案,或者想要更改答案,但是试卷上已经有了痕迹。这时候,我们就需要一些工具来擦除答案。以下是几个简单的步骤,让…

[每周一更]-(第58期):选购佳能变焦镜头 EF-S 18-200mm F/3.5-5.6 IS的心得

参考地址: https://www.canon.com.cn/purchase/onlinesale/index3.html?typejdhttps://www.canon.com.cn/overview/efwidezoom.html 讲在买之前 由于没有买全画幅,买了残幅,好处是能选的镜头有限,不用太费钱了,需要…

C和C++的区别(6)字符串

目录 一,字符 二,C语言字符串 1,字符串的表示 2,输入输出 3,常用函数 三,string类 1,定义,初始化,输入输出 一,字符 类型:char 输入&…

sealos安装k8s

一、前言 1、我前面文章有写过使用 kubeadm 安装的方式,大家可以去参考 (二)k8s集群安装,有一系列的k8s文章说明 2、安装k8s的方式有很多 kubeadmsealoskubespray等等 3、关于sealos来安装 k8s ,也是非常建议大家去…

ACM输入总结

目录 一,输入结构 1,一级输入结构 2,嵌套输入结构 二,一级输入结构 HDU 1089 AB for Input-Output Practice (I) HDU 1090 AB for Input-Output Practice (II) HDU 1091 AB for Input-Output Practice (III) HDU 1095 AB …

浅谈智慧消防助力现代社会火灾防控 安科瑞 顾语欢

摘 要:随着我国经济水平的不断提高,科学技术取得了长足进步。科学技术的进步推动着社会不断前进,改变了各行各业的人们的生活。随着各种新型的技术尤其是人工智能技术的出现,社会进入了智能化时代。消防作为维护我们生活的一道重要…

ava算法_ 跳跃游戏(LeetCode_Hot100)

题目描述:给你一个非负整数数组 ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。nums 判断你是否能够到达最后一个下标,如果可以,返回 ;否则,返回 。truefalse 获得更…

[保研/考研机试] KY7 质因数的个数 清华大学复试上机题 C++实现

描述 求正整数N(N>1)的质因数的个数。 相同的质因数需要重复计算。如1202*2*2*3*5&#xff0c;共有5个质因数。 输入描述&#xff1a; 可能有多组测试数据&#xff0c;每组测试数据的输入是一个正整数N&#xff0c;(1<N<10^9)。 输出描述&#xff1a; 对于每组数…

vite+vue3项目环境搭建

1.安装 npm init vite 2.输入项目名称 vue3-project 3.选择框架 说明&#xff1a;vue 4.选择类别 说明&#xff1a;JavaScript 5.进入文件夹 cd vue3-project yarn npm run dev 6.打开local