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

手写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();}}
}

相关文章:

  • 飞鸟写作能用吗 #笔记#笔记
  • excel处理_多个excel文件合并
  • Pear-rec:一键开启多功能捕捉分享,告别繁琐操作!
  • Python Flask 将数据传递给前端
  • matlab 将矩阵写入文件
  • 【python】flask服务端响应与重定向处理
  • 哈工大sse C语言 困难
  • Spring Boot 自动化单元测试类的编写过程
  • ②零基础MySQL数据库-MySQL约束
  • 从零开始一步一步掌握大语言模型---(1-写在最开始)
  • 2024网络安全数据安全加固类资料合集
  • 选择word中的表格VBA
  • 数据结构面试常见问题之串的模式匹配(KMP算法)系列-大师改进实现以及原理
  • 【蓝牙协议栈】【BLE】低功耗蓝牙配对绑定过程分析(超详细)
  • rollup打包起手式
  • 0x05 Python数据分析,Anaconda八斩刀
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • 30天自制操作系统-2
  • CAP 一致性协议及应用解析
  • CSS居中完全指南——构建CSS居中决策树
  • ECMAScript入门(七)--Module语法
  • JavaScript 基础知识 - 入门篇(一)
  • JavaScript设计模式与开发实践系列之策略模式
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • mysql外键的使用
  • ViewService——一种保证客户端与服务端同步的方法
  • 测试如何在敏捷团队中工作?
  • 基于游标的分页接口实现
  • 前端相关框架总和
  • 前端之React实战:创建跨平台的项目架构
  • 阿里云服务器购买完整流程
  • 大数据全解:定义、价值及挑战
  • 第二十章:异步和文件I/O.(二十三)
  • ​力扣解法汇总946-验证栈序列
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #mysql 8.0 踩坑日记
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • %@ page import=%的用法
  • (1)bark-ml
  • (3)nginx 配置(nginx.conf)
  • (8)STL算法之替换
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (二)hibernate配置管理
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (十六)Flask之蓝图
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转载)利用webkit抓取动态网页和链接
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .net core Swagger 过滤部分Api
  • .net 发送邮件
  • .NET 指南:抽象化实现的基类
  • .NET/C# 使窗口永不获得焦点
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .net打印*三角形
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)