再谈jdk的代理

文章迁移自语雀。

其实jdk的代理模式已经说了很多次了,现在是北京时间2020年2月16日23:15:06, 躺在床上打字,手冰冷的,写完这个总结就睡觉的.
现在手感觉没啥知觉了, 好冷, 现在是2020年2月16日23:50:51., 写了45分钟. 关电脑准备睡觉,明天看jdk的动态代理实现,学习大师的作品,对比自己的实现差异.

综述

jdk中的代理,就是三种
1.继承
2.聚合
1,2属于静态代理
3.动态代理

下面我们依次说这三种方式.

1.继承
就是使用一个新的类,去继承原来的类,对原来的类对方法的增强.

使用的实例代码如下:
public interface UserService {
   public void login();
}
public class UserServiceImpl implements UserService {
   @Override
   public void login() {
       System.out.println("好想念程程,不知道她睡觉了没有");
   }
}
public class TimeExtends extends UserServiceImpl {
   @Override
   public void login() {
       System.out.println("继承的代理");
       super.login();
   }
}

缺点很明显, 需要继承, 而且随着功能的增加, 要不断的继承, 体系混乱,越来越复杂. 最后谁就不懂了.

2.聚合
因为是持有原来的对象,所以又交聚合,这个其实就是一种设计模式了,用的很巧妙.

public class LogExtends implements UserService {
   private UserService userService;
   public LogExtends(UserService userService) {
       this.userService = userService;
   }
   @Override
   public void login() {
       System.out.println("这是静态代理的方法");
       userService.login();
   }
}

相对于第一种有了很明显的进步, 耦合性大大的降低,但是如果需要增强的功能太多,也是很复杂的,而且要增强的功能往往不明确,不知道去实现谁的接口.

3.动态代理
这次我们手写一个自己的动态代理.
我们模仿第二种方式,动态的生成一个.java文件, 再编译成.calss文件,最后加载到jvm中,生成对象,调用新的对象的方法,就得到的增强的目的,而且对用户是透明的.

public class ProxyUtil {
   private final static String Line="\n";
   private final static String Tab="\t";
   /**
    * 生成LogExtends 一样的接口.
    * @param target
    * @return
    */
   public static Object getProxyObject(Object target){
       StringBuilder sb = new StringBuilder("package com.onyx.proxy;").append(Line);
       sb.append(Line);
       sb.append("import").append(" ");
       Class<?> targetClass = target.getClass();
       Class<?> anInterface = targetClass.getInterfaces()[0];
       String interfaceSimpleName = anInterface.getSimpleName();
       sb.append(anInterface.getName()).append(";").append(Line).append(Line);
       sb.append("public class $ProxyClass implements ");
       sb.append(interfaceSimpleName).append("{").append(Line);
       sb.append(Line);
       sb.append(Tab).append("private").append(" ").append(interfaceSimpleName).append(Tab).append("proxyObject").append(";").append(Line).append(Line);
       //构造方法
       sb.append(Tab).append("public").append(Tab).append("$ProxyClass(").append(interfaceSimpleName).append(Tab).append("param")
               .append("){").append(Line).append(Tab).append(Tab).append("this.proxyObject=param;").append(Line)
               .append(Tab).append("}").append(Line).append(Line);
       String methodName = anInterface.getMethods()[0].getName();
       sb.append(Tab).append("public").append(Tab).append("void").append(Tab).append(methodName)
               .append("(){").append(Line);
       sb.append(Tab).append(Tab).append("System.out.println(\"这是增强的log方法\");").append(Line);
       sb.append(Tab);
       sb.append(Tab).append("proxyObject.").append(methodName).append("();").append(Line);
       sb.append(Tab).append("}").append(Line).append("}");
       System.out.println(sb.toString());
       return null;
   }
}

这个生成的结构就是和LogExtends.java是一样的,只是我们自己拼接出来的,生成的结果是:

image.png


这是生成的.java结构, 我打印出来了,
至于怎么加载到jvm中,各位自己想办法. 有了string字符串, 保存成.java文件,在找到文件加载就可以了.
这个不是本文的重点,就不说了,手好冰啊.

其实这是我们自己实现的一个简单版本的动态代理,这个有待于优化
1.调用方法的参数(这里直接写了空参数) 进行类型的获取, 填充,
2.方法的返回值(直接写了void), 获取返回类型, 判断是都void ,返回
3.类的多接口实现(我这里就直接取了第一个接口).

最后是我们的测试类:
public class ChengCheng {
   public static void main(String[] args) {
       //new TimeExtends().login();
       //new LogExtends(new UserServiceImpl()).login();
       UserService object = (UserService)ProxyUtil.getProxyObject(new UserServiceImpl());
   }
}

上面的代码其实还有个问题,代理的逻辑,我们没有抽离出来, 这个要封装很多层才好传递进去,最好是用接口的形式传递参数.

下面我们来看jdk中是怎么代理的.
//jdk的代理
UserService service = (UserService) Proxy.newProxyInstance(
ChengCheng.class.getClassLoader(),        new Class[]{UserService.class},
new MyInvokeHandle(new UserServiceImpl()));

service.login();

image.png


其中719行代码, 就是获取到生成的代理类的class类对象, 所以这一行代码是关键, 下面的代码就是利用这个class对象进行创建一个对象,然后返回回去.

image.png


第408行的注释, 说如果没有就使用ProxyClassFactory创建一个,否则直接从缓存里面拿, 我们不看缓存的拿去, 就是一个Map, 没事好看的. 看看这个ProxyClassFactory类.他是静态的内部类.

image.png


第639行, 是生成了代理类文件的二进制流, 所以我们看看这里.
 

image.png


第110行生成了这个类的class文件. 这个就非常的关键了.其实就是不断的拼接生成了.class文件, 牛逼哄哄的不得了. 哈哈哈


最后生成了返回, 第642行把一个二进制的class文件变成了 一个class对象返回去了,

image.png





看到这里, 就看不下去了,还想看就去下载openjdk的源码, 去研究下,怎么把byte[] 变成class对象.

image.png





 

1 人点赞

  • 长河

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp 编译到模拟器(mumu)

一开始我是用逍遥模拟器&#xff0c;但这个玩意突然不好使了&#xff0c;一直加载卡在这页面 1、下载 官网下载&#xff1a;mumu模拟器12 2、打开mumu多开器&#xff0c;在右上角adb查看端口号 3、打开mumu模拟器 4、打开HBuiderX 工具—设置—运行配置 5、配置电脑的系统…

驱动开发11-1 编写IIC驱动-读取温湿度数据

头文件 head.h #ifndef __HEAD_H__ #define __HEAD_H__ #define GET_HUM _IOR(m, 1, int) #define GET_TEM _IOR(m, 0, int) #endif 应用程序 si7006.c #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #inc…

「更新」Macos屏幕录像工具:ScreenFlow

mac电脑屏幕截图工具哪个好&#xff1f;ScreenFlow是Mac上的一款优秀的屏幕录像软件&#xff0c;它不仅具有屏幕录制功能&#xff0c;还具有视频编辑功能。以下是对ScreenFlow的一些详细介绍&#xff1a; 首先&#xff0c;ScreenFlow可以捕获摄像机、麦克风和计算机音频&#…

Redis中String类型的命令

目录 Redis中的内部编码 redis的数据结构和内部编码 Redis中的String类型 String类型的常见命令 set get mget mset String类型的计数命令 incr incrby decr incrbyfloat 其他命令 append getrange setrange strlen String类型的内部编码 Redis中的内部编码…

win10-mmgen安装/cyclegan运行问题记录

mmconda环境&#xff1a; conda&#xff1a; CUDA 11.3 conda install pytorch1.11.0 torchvision0.12.0 torchaudio0.11.0 cudatoolkit11.3 -c pytorch pip install mmcv-full1.5.0 -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.11.0/index.html 成功运行 c…

无需使用jadx-gui和mac电脑获取app备案公钥的方法

由于2023年&#xff0c;国家要求上架的app必须备案&#xff0c;因此app备案成为了很多公司迫切的需求。 备案的时候&#xff0c;需要填写app公钥&#xff0c;MD5值等参数&#xff0c;这些参数对于不熟悉加密技术的人来说&#xff0c;简直是无从下手&#xff0c;因为目前的开发…

安防视频监控平台EasyCVR出现目录在线,通道离线的问题该如何解决?

视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能…

VR全景技术在文化展示与传播中有哪些应用?

引言&#xff1a; 随着科技的不断进步&#xff0c;虚拟现实&#xff08;VR&#xff09;全景技术已经成为文化展示与传播领域的一项重要工具。那么VR全景技术是如何改变文化展示与传播方式&#xff0c;VR全景技术又如何推动文化的传承和普及呢&#xff1f; 一&#xff0e;VR技术…

【易售小程序项目】后端部署、Uniapp项目Web部署

文章目录 Uniapp项目Web打包部署为什么不部署小程序Web打包前对项目进行调整网站、小程序切换增加constant.js来控制常量将js绑定到main.js的全局变量中 WebSocket差异监听键盘呼出导航条打包部署 后端项目打包部署打包前准备打包部署 Uniapp项目Web打包部署 为什么不部署小程…

【广州华锐互动】VR虚拟现实技术在森林防火教学中的应用

在探索大自然的神秘面纱时&#xff0c;我们往往会遇到一些意想不到的风险&#xff0c;其中之一就是森林火灾。森林火灾是一种毁灭性的自然灾害&#xff0c;可以在短时间内摧毁大片森林&#xff0c;对人类和动物的生存环境造成严重影响。然而&#xff0c;通过3D仿真技术&#xf…

使用Dockerfile生成docker自定义镜像

Dockerfile常用指令 • FROM 构建镜像基于哪个镜像 • MAINTAINER 镜像维护者姓名或邮箱地址 • RUN 构建镜像时运行的指令,执行一条RUN镜像就会叠加一层&#xff0c;因此RUN尽可能一条写完 • ADD 拷贝文件或目录到容器中&#xff0c;如果是URL或压缩包便会自动下载或自动解压…

Linux之centos7安装配置及Linux常用命令

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《LInux实战开发》。&#x1f3af;&#x1f3af; …

Linux新建普通用户无法使用退格键与tab键

创建普通用户 useradd mulan passwd mulan 切换用户 su mulan 发现普通用户无法使用退格键与tab键&#xff0c;一直显示如图 如图&#xff0c;按退格键(Backspace)、删除键出现 ‘^H’ 符号&#xff0c;tab键也不能自动拼写 这是新用户下的普通bash配置都没有&#xff0c;从…

sw 怎么装新版本

我们在安装solidworks时&#xff0c;有时候会提示A newer version of this applic ation is already installed. Installation stopped.如下图所示 这时候需要点继续安装 然后会出现下图所示情况&#xff0c;vba7.1安装未成功 这是因为我们电脑中以前安装过更高版本的solidw…

【STL】:list用法详解

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关list的使用&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构…

利用移动互联、物联网、智能算法、地理信息系统、大数据分析等信息技术开发的智慧工地云平台源码

智慧工地是指利用移动互联、物联网、智能算法、地理信息系统、大数据挖掘分析等信息技术&#xff0c;提高项目现场的“人•机•料•法•环•安”等施工要素信息化管理水平&#xff0c;实现工程施工可视化智能管理&#xff0c;并逐步实现绿色生态建造。 技术架构&#xff1a;微…

WheatA 轻量级生态数据软件

无论是在工作还是上学期间&#xff0c;大家想要做一个科研项目或者市场调查时&#xff0c;往往需要大量的数据用于分析总结&#xff0c;这时获得优质的数据就显得额外重要&#xff0c;数据的优劣往往决定了项目结果的好坏。数据来源的主要渠道主要有两种&#xff1a;无非是去数…

Redis常见的全局命令

Redis中最核心的两个命令set和get 两个最核心的命令就是get和set. redis是按照键值对的方式来存储数据的,所以set就表示把key-value存储进去,get表示根据key来查询对应的value. 需要注意的是,必须进入redis客户端才能输入redis命令. 此处的key和value都是字符串类型.对于上述…

CLion 2023.2.2(C ++ IDE智能代码编辑器)

CLion 2023是一款跨平台C/C集成开发环境&#xff08;IDE&#xff09;。它为Mac用户提供了高效的编程体验&#xff0c;帮助程序员们在Mac平台上进行C/C开发。 CLion 2023支持多种编译器和调试器&#xff0c;并具有强大的代码分析和导航功能。它还为用户提供了许多便捷的工具和插…

同时标注分割、检测、多分类属性的工具

1、 https://blog.csdn.net/minstyrain/article/details/82385580/ 2、 https://zhuanlan.zhihu.com/p/656703406
最新文章