手写实现JDK的动态代理
时间:2020-01-03
本文章向大家介绍手写实现JDK的动态代理,主要包括手写实现JDK的动态代理使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Person接口
package com.zhoucong.proxy.jdk; public interface Person { // 寻找真爱 void findlove(); }
人物实现类
package com.zhoucong.proxy.jdk; public class Zhangsan implements Person{ @Override public void findlove() { System.out.println("我叫张三,性别女,我找对象的要求如下:\n"); System.out.println("高富帅"); System.out.println("有房有车"); System.out.println("身高180cm以上,体重70kg"); } }
自定义InvocationHandler接口
package com.zhoucong.custom; import java.lang.reflect.Method; public interface GPInvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
代理类
package com.zhoucong.custom; import java.lang.reflect.Method; import com.zhoucong.proxy.jdk.Person; public class GPMeiPo implements GPInvocationHandler{ private Person target; // 获取被代理人的个人资料 public Object getInstance(Person target) throws Exception { this.target = target; Class clazz = target.getClass(); System.out.println("被代理对象的class是:"+ clazz); return GPProxy.newProxyInstance(new GPClassLoader(), clazz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是媒婆!"); System.out.println("开始信息海选"); System.out.println("-------------"); method.invoke(this.target, args); System.out.println("-------------"); System.out.println("如果合适的话,就准备办事"); return null; } }
生成代理对象类
package com.zhoucong.custom; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; /** * 生成代理对象的代码 * * @author ZhouCong * */ public class GPProxy { private static String ln = "\r\n"; public static Object newProxyInstance(GPClassLoader loader, Class<?>[] interfaces, GPInvocationHandler h) throws IllegalArgumentException { try { // 1.生成源代码 String proxySrc = generateSrc(interfaces[0]); // 2.将生成的源代码输出到磁盘,保存.java文件 String path = GPProxy.class.getResource("").getPath(); File f = new File(path + "$Proxy0.java"); FileWriter fw = new FileWriter(f); fw.write(proxySrc); fw.flush(); fw.close(); // 3.编译源代码,并且生成.class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null); Iterable iterable = manager.getJavaFileObjects(f); CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable); task.call(); manager.close(); // 4.将class文件中的内容,动态加载到JVM中 Class<?> proxyClass = loader.findClass("$Proxy0"); Constructor<?> constructor = proxyClass.getConstructor(GPInvocationHandler.class); f.delete(); //删除生成的Java文件 // 5.返回被代理后的代理对象 return constructor.newInstance(h); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 生成代码 * @param interfaces * @return */ private static String generateSrc(Class<?> interfaces) { StringBuffer src = new StringBuffer(); src.append("package com.zhoucong.custom;" + ln); src.append("import java.lang.reflect.Method;" + ln); src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln); src.append("GPInvocationHandler h;" + ln); src.append("public $Proxy0(GPInvocationHandler h){" + ln); src.append("this.h = h;" + ln); src.append("}" + ln); for (Method m : interfaces.getMethods()) { src.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln); src.append("try {" + ln); src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" + m.getName() +"\",new Class[]{});" + ln); src.append("this.h.invoke(this,m,null);" + ln); src.append("} catch(Throwable e){e.printStackTrace();}" + ln); src.append("}" + ln); } src.append("}"); return src.toString(); }; }
自定义ClassLoader类
package com.zhoucong.custom; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * 代码生成、编译、重新动态load到JVM中 * @author ZhouCong * */ public class GPClassLoader extends ClassLoader{ private File baseDir; public GPClassLoader() { String path = GPClassLoader.class.getResource("").getPath(); this.baseDir = new File(path); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = GPClassLoader.class.getPackage().getName() + "." + name; if(baseDir != null) { File classFile = new File(baseDir,name.replaceAll("\\.", "/")+".class"); if(classFile.exists()) { FileInputStream in = null; ByteArrayOutputStream out = null; try { in = new FileInputStream(classFile); out = new ByteArrayOutputStream(); byte [] buff = new byte[1024]; int len; while((len = in.read(buff)) != -1) { out.write(buff,0,len); } return defineClass(className,out.toByteArray(),0,out.size()); }catch (Exception e) { e.printStackTrace(); }finally { if(null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != out) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } // 删除class文件 classFile.delete(); } } } return null; } }
运行类
package com.zhoucong.proxy.jdk; import com.zhoucong.custom.GPMeiPo; public class TestFindLove { public static void main(String[] args) { try { Person obj = (Person) new GPMeiPo().getInstance(new Zhangsan()); System.out.println(obj.getClass()); obj.findlove(); } catch (Exception e) { e.printStackTrace(); } } }
原文地址:https://www.cnblogs.com/itzhoucong/p/12144339.html
- 1088: [SCOI2005]扫雷Mine
- 1029: [JSOI2007]建筑抢修
- 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)
- 关于类的对象创建与初始化
- 1191: [HNOI2006]超级英雄Hero
- 2005: [Noi2010]能量采集
- 1067: [SCOI2007]降雨量
- 2761: [JLOI2011]不重复数字(哈希表)
- 1297: [SCOI2009]迷路
- Javascript DOM操作实例
- 2431: [HAOI2009]逆序对数列
- JavaScript实例---表格隔行变色以及移入鼠标高亮
- 1022: [SHOI2008]小约翰的游戏John
- Javascript数组
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- docker实现Mongodb复制集
- Centos7搭建LAMP+Typecho个人博客
- [Centos7]搭建postfix邮件服务器
- [Docker]手动配置docker网络
- [Centos7]使用GPG加密和解密文件
- [Centos7]设置禁ping
- [Centos7]open读取文件报错:TypeError
- [Centos7]对硬盘进行分区及自动挂载
- [Centos7]extundelete恢复误删除数据
- [Centos7]自定义开机自启脚本
- [Centos7]安装scapy模块
- [Centos7]安装rrdtool模块
- [Centos7]XlsxWriter模块安装
- [Centos7]安装pycurl
- [Centos7]python-nmap端口扫描