手写JDK Proxy实现InvocationHandler的Invoker

JDKProxy生成对象的步骤如下:
1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。
2、JDKProxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接
口。
3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体
现)。
4、编译新生成的Java代码.class。
5、再重新加载到JVM中运行。
以上这个过程就叫字节码重组。JDK中有一个规范,在ClassPath下只要是$开头的class
文件一般都是自动生成的。

package com.sp.demo.proxy;/*** @author : lssffy* @Description :* @date : 2024/3/8 10:25*/
public interface OneDay {void eat();void play();void sleep();
}
package com.sp.base.proxyhandler;import java.lang.reflect.Method;/*** @author : lssffy* @Description :* @date : 2024/3/21 14:41*/
public interface SInvocationHandler {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
package com.sp.base.proxyhandler;import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;/*** @author : lssffy* @Description :* @date : 2024/3/21 14:42*/
public class SProxy {private static final String ln = "\r\n";public static Object newProxyInstance(SClassLoader classLoader,Class<?> [] interfaces,SInvocationHandler h){try {//动态生成源代码。java文件String src = generateSrc(interfaces);//Java文件输出磁盘String filePath = SProxy.class.getResource("").getPath();File f = new File(filePath + "$Proxy0.java");FileWriter fw = new FileWriter(f);fw.write(src);fw.flush();fw.close();//把生成的。java文件编译成。class文件JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);Iterable iterable = manager.getJavaFileObjects(f);JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable);task.call();manager.close();//把编译生成的。class文件加载到jvm中Class proxyClass = classLoader.findClass("$Proxy0");Constructor c = proxyClass.getConstructor(SInvocationHandler.class);f.delete();//返回字节码重组以后的新的代理对象return c.newInstance(h);}catch (Exception e){e.printStackTrace();}return null;}private static String generateSrc(Class<?>[] interfaces) {StringBuffer sb= new StringBuffer();sb.append("package com.sp.base.proxyhandler;" +ln);sb.append("import com.sp.demo.proxy.OneDay;" + ln);sb.append("import java.lang.reflect.*;" +ln);sb.append("public class $Proxy0 implements " + interfaces[0].getName()+ "{"+ln);sb.append("SInvocationHandler h;"+ ln);sb.append("public $Proxy0(SInvocationHandler h) { "+ln);sb.append("this.h = h;");sb.append("}"+ ln);for(Method m : interfaces[0].getMethods()){Class<?>[] params= m.getParameterTypes();StringBuffer paramNames=new StringBuffer();StringBuffer paramValues=new StringBuffer();StringBuffer paramClasses= new StringBuffer();for(int i= 0;i < params.length; i++){Class clazz=params[i];String type=clazz.getName();String paramName= toLowerFirstCase(clazz.getSimpleName());paramNames.append(type + "" + paramName);paramValues.append(paramName);paramClasses.append(clazz.getName() + ".class");if(i > 0&& i< params.length-1){paramNames.append(",");paramClasses.append(",");paramValues.append(",");}}sb.append("public " +m.getReturnType().getName() + " " + m.getName() +"(" +paramNames.toString() + "){"+ ln);sb.append("try{"+ ln);sb.append("Method m="+interfaces[0].getName()+".class.getMethod(\""+m.getName()+ "\",new Class[]{"+paramClasses.toString() + "});" +ln);sb.append((hasReturnValue(m.getReturnType()) ?"return " : "") +getCaseCode("this.h.invoke(this,m,new Object[]{"+paramValues+"})",m.getReturnType())+";"+ln);sb.append("}catch(Error _ex){ }");sb.append("catch(Throwable e){"+ ln);sb.append("throw new UndeclaredThrowableException(e);" +ln);sb.append("}");sb.append(getReturnEmptyCode(m.getReturnType()));sb.append("}");}sb.append("}"+ ln);return sb.toString();}private static Map<Class,Class> mappings = new HashMap<Class,Class>();static {mappings.put(int.class,Integer.class);}private static String getReturnEmptyCode(Class<?> returnType) {if(mappings.containsKey(returnType)){return "return 0;";}else if(returnType ==void.class){return "";}else{return"return null;";}}private static String getCaseCode(String s, Class<?> returnType) {if(mappings.containsKey(returnType)){return "(("+mappings.get(returnType).getName() + ")"+ s+ ")."+returnType.getSimpleName() +"Value()";}return s;}private static boolean hasReturnValue(Class<?> returnType) {return returnType != void.class;}private static String toLowerFirstCase(String simpleName) {char [] chars = simpleName.toCharArray();chars[0] += 32;return String.valueOf(chars);}
}
package com.sp.base.proxyhandler;import java.io.*;/*** @author : lssffy* @Description :* @date : 2024/3/21 14:44*/
public class SClassLoader extends ClassLoader{private File classPathFile;public SClassLoader(){String classPath = SClassLoader.class.getResource("").getPath();this.classPathFile = new File(classPath);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String className = SClassLoader.class.getPackage().getName() + "." + name;if (classPathFile != null) {File classFile = new File(classPathFile,name.replace("\\", "/") + ".class");if(classFile.exists()) {FileInputStream fis = null;ByteArrayOutputStream out = null;try {fis = new FileInputStream(classFile);out = new ByteArrayOutputStream();byte [] buff = new byte[1024];int len;while((len=fis.read(buff))!=-1){out.write(buff,0,len);}return defineClass(className,out.toByteArray(),0,out.size());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(null!=fis){try {fis.close();} catch (IOException e) {e.printStackTrace();}}if(null!=out){try {out.close();} catch (IOException e) {e.printStackTrace();}}}}}return null;}
}
package com.sp.demo.proxy;import com.sp.base.proxyhandler.SClassLoader;
import com.sp.base.proxyhandler.SInvocationHandler;
import com.sp.base.proxyhandler.SProxy;import java.lang.reflect.Method;/*** @author : lssffy* @Description :* @date : 2024/3/21 14:15*/
public class InvocationHandlerJDK implements SInvocationHandler {private Object target;public Object getInstance(Object target) {this.target = target;Class<?> targetClass = target.getClass();return SProxy.newProxyInstance(new SClassLoader(),targetClass.getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object obj = method.invoke(this.target, args);after();return obj;}private void before(){System.out.println("start runtime invocation");}private void after(){System.out.println("end runtime invocation");}}
package com.sp.demo.proxy;/*** @author : lssffy* @Description :* @date : 2024/3/8 10:26*/
public class LaoWang implements OneDay{@Overridepublic void eat() {System.out.println("准备碗筷");System.out.println("开始吃饭");System.out.println("收拾碗筷");}@Overridepublic void play() {System.out.println("打开电脑");System.out.println("登录账号");System.out.println("开始玩");}@Overridepublic void sleep() {System.out.println("开始洗澡");System.out.println("躺倒床上");System.out.println("开始睡觉");}
}
package com.sp.demo.proxy;/*** @author : lssffy* @Description :* @date : 2024/3/8 10:33*/
public class Test {public static void main(String[] args) {try {OneDay oneDay1 = (OneDay) new InvocationHandlerJDK().getInstance(new LaoWang());oneDay1.play();oneDay1.eat();oneDay1.sleep();}catch(Exception e){e.printStackTrace();}}
}

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

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

相关文章

网关层针对各微服务动态修改Ribbon路由策略

目录 一、介绍 二、常规的微服务设置路由算法方式 三、通过不懈努力&#xff0c;找到解决思路 四、验证 五、总结 一、介绍 最近&#xff0c;遇到这么一个需求&#xff1a; 1、需要在网关层&#xff08;目前使用zuul&#xff09;为某一个服务指定自定义算法IP Hash路由策…

JUC并发编程(五)

1、java内存模型 Java内存模型&#xff08;Java Memory Model&#xff0c;JMM&#xff09;是Java编程语言中用于处理并发编程的一组规则和规范。它定义了Java程序中多线程之间如何交互以及内存如何被共享和访问的规则。它定义了主内存&#xff0c;工作内存的抽象概念&#xff0…

一文让你简单了解跨境电商需要购买堡垒机的几大原因

随着互联网技术的快速发展&#xff0c;跨境电商蓬勃发展&#xff0c;但发展过程中网络安全问题日益凸显。因此不少跨境电商企业购买了堡垒机。这是为什么呢&#xff1f;一文让你简单了解跨境电商需要购买堡垒机的几大原因。 一文让你简单了解跨境电商需要购买堡垒机的几大原因 …

代码随想录day26(2)二叉树:二叉搜索树中的众数(leetcode501)

题目要求&#xff1a;给定一个有相同值的二叉搜索树&#xff08;BST&#xff09;&#xff0c;找出 BST 中的所有众数。结点左子树中所含结点的值小于等于当前结点的值&#xff0c;结点右子树中所含结点的值大于等于当前结点的值。 思路&#xff1a;如果不考虑二叉搜索树&#…

TCP机械臂控制

通过w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 注意&#xff1a;关闭计算机的杀毒软件&#xff0c;电脑管家&#xff0c;防火墙 1&#xff09;基于TCP服务器…

最近接到一个大项目,给公司设计抢商品代金劵业务

我们公司是做汽车金融方面的工作&#xff0c;在业内还挺大。目前单量来源于2&#xff0c;3线城市&#xff0c;随着大环境越老越差位了吸引他们&#xff0c; 公司决定给全国的客户&#xff0c;销售等发一些商品 1.总体学习了京东开源秒杀系统设计思路和方案。 我们公司决定进行…

博途PLC 高速计数器复位功能块(HC_Reset)

高速计数器的使用和编码器应用请参考下面文章链接: 1、普通开关计米功能块(博途高速计数器应用) https://rxxw-control.blog.csdn.net/article/details/132354435https://rxxw-control.blog.csdn.net/article/details/1323544352、S7-1200PLC编码器转速测量功能块(高速计数…

c++算法学习笔记 (15) 质数

1.试除法判断某个数是否为质数 #include <iostream> using namespace std; const int N 50005; bool is_prime1(int n) { // 暴力写法&#xff1a;O(n)if (n < 2)return false;for (int i 2; i < n; i){if (n % i 0)return false;}return true; } // 优化&…

含“AI”量上涨,智能模组SC208系列助力智慧零售全场景高质发展

AI正重塑智慧零售产业&#xff0c;加速零售在采购、生产、供应链、销售、服务等方面改善运营效率和用户体验。零售行业经历了从线下到线上再到全渠道融合发展过程&#xff0c;“提质、降本、增效、高体验”是亘古不变的商业化与智能化方向。含“AI”量逐渐上涨的智慧零售正经历…

Git——IDEA中的使用详解

目录 Git1、IDEA中配置Git2、将本地项目推送到远程仓库2.1、创建项目远程仓库2.2、初始化本地仓库2.3、连接远程仓库2.4、提交到本地仓库2.5、推送到远程仓库 3、克隆远程仓库到本地4、基本操作4.1、代码提交到暂存区4.2、暂存区代码提交到本地库4.3、推送到远程仓库4.4、撤销本…

VMware的二次开发

VMware的Virtual Disk format https://www.vmware.com/app/vmdk/?srcvmdk 在这个文档中描述了VMDK的格式。 当前VMware提供了多种开发库&#xff1a; vsphere soap api: provide the interface to manage vshpere. Virtual Disk Development Kit&#xff1a;VMware Virtu…

HJ3 明明的随机数

HJ3 明明的随机数 题目描述 明明生成了&#xfffd;N个1到500之间的随机整数。请你删去其中重复的数字&#xff0c;即相同的数字只保留一个&#xff0c;把其余相同的数去掉&#xff0c;然后再把这些数从小到大排序&#xff0c;按照排好的顺序输出。 数据范围&#xff1a; 1≤…

nginx反代后java的request.getScheme获取不到https的解决办法

在实际工作中,经常会用到nginx反向代理应用,访问https页面Java 通过request.getScheme()获取不到https协议,或者response.sendRedirect重定向是http,而不是我们想要的https。 问题原因 经过反代后,协议信息没有转发到后端,或者后端没有设置 protocolHeader nginx配置 …

leetCode刷题 18. 四数之和

目录 注意&#xff1a;正常提交后有问题。 1. 思路 2. 解题方法 2.1 排序数组 2.2 双指针遍历 3. 复杂度 4. Code 题目&#xff1a; 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], …

大数据面试总结 四

1、当hadoop集群中某一个节点挂了&#xff0c;内部数据流程是如何进行的&#xff1f; 每一个datanode都会定期向namenode发送heardbeat消息&#xff0c;当一段时间namenode没有接收到某一个datanode的消息&#xff0c;此时namenode就会将该datanode标记为死亡&#xff0c;并不…

TouchGFX之性能测量

TouchGFX Core开放了几个信号&#xff0c;可用于测量性能。 当这些信号在内部触发时&#xff0c;用户可在应用程序中同步触发单个GPIO&#xff0c;从而实现“渲染时间”和其他有用信号的可视化。 信号在GPIO.hpp中定义 /* 用于操作GPIO的接口类&#xff0c;以便在目标硬件上进…

力扣---完全平方数

思路&#xff1a; 还是比较好想的&#xff0c;g[i]定义为和为 i 的完全平方数的最少数量。那么递推关系式是g[i]min(g[i-1],g[i-4],g[i-9],...)1&#xff0c;数组初始化是g[0]0,g[1]1。注意这里要对g[0]初始化&#xff0c;&#xff08;举个例子&#xff09;因为在遍历到g[4]时&…

数据库迁移测试

数据库 数据源变更&#xff1a;数据库名称、数据库类型等&#xff0c;一般情况下在同类型的数据库之间迁移比较常见&#xff0c;但是也存在不同类型的数据库之间的迁移&#xff0c;例如&#xff1a;oracle到MySQL等等&#xff0c;非关系型数据库到关系型&#xff0c;关系型到非…

14 网络管理与网络安全(1)

1.网络管理 在网络管理中&#xff0c;一般采用网络管理者-网管代理模型。管理者实质上是运行在计算机操作系统之上的一组应用程序&#xff0c;代理位于被管理的设备内部。一个管理者可以和多个代理之间进行信息交换。网络管理一般采用集中式网络管理或者分布式网络管理。集中式…

基于Springboot+Vue3的大学生毕业作业设计之—招投标分析系统

有系统开发需求可私信我提供帮助哦 ~ 部分 import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.L…