日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

高仿真 JDK Proxy手写实现

發布時間:2024/4/13 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高仿真 JDK Proxy手写实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

不僅知其然,還得知其所以然。既然 JDK Proxy功能如此強大,那么它是如何實現的呢?我們現在來探究一下原理,并模仿 JDK Proxy自己動手寫一個屬于自己的動態代理。我們都知道 JDK Proxy采用字節重組,重新生的對象來替代原始的對象以達到動態代理的目的。JDK Proxy生成對象的步驟如下:

1、拿到被代理對象的引用,并且獲取到它的所有的接口,反射獲取。

2、JDK Proxy類重新生成一個新的類、同時新的類要實現被代理類所有實現的所有的接口。

3、動態生成 Java代碼,把新加的業務邏輯方法由一定的邏輯代碼去調用(在代碼中體現)。

4、編譯新生成的 Java代碼.class。

5、再重新加載到 JVM中運行。

以上這個過程就叫字節碼重組。JDK中有一個規范,在 ClassPath下只要是$開頭的?class文件一般都是自動生成的。那么我們有沒有辦法看到代替后的對象的真容呢?做一個這樣測試,我們從內存中的對象字節碼通過文件流輸出到一個新的 class文件,然后,利用反編譯工具查看 class的源代碼。來看測試代碼:

創建 GPProxy類:?

/*** 用來生成源代碼的工具類* Created by Tom.*/ public class GPProxy {public static final String ln = "\r\n";public static Object newProxyInstance(GPClassLoader classLoader, Class<?> [] interfaces, GPInvocationHandler h){try {//1、動態生成源代碼.java文件String src = generateSrc(interfaces);// System.out.println(src);//2、Java文件輸出磁盤String filePath = GPProxy.class.getResource("").getPath(); // System.out.println(filePath);File f = new File(filePath + "$Proxy0.java");FileWriter fw = new FileWriter(f);fw.write(src);fw.flush();fw.close();//3、把生成的.java文件編譯成.class文件JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);Iterable iterable = manage.getJavaFileObjects(f);JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);task.call();manage.close();//4、編譯生成的.class文件加載到JVM中來Class proxyClass = classLoader.findClass("$Proxy0");Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);f.delete();//5、返回字節碼重組以后的新的代理對象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.leon.vip.pattern.proxy.dynamicproxy.gpproxy;" + ln);sb.append("import com.leon.vip.pattern.proxy.Person;" + ln);sb.append("import java.lang.reflect.*;" + ln);sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);sb.append("GPInvocationHandler h;" + ln);sb.append("public $Proxy0(GPInvocationHandler 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<?> returnClass){if(mappings.containsKey(returnClass)){return "return 0;";}else if(returnClass == void.class){return "";}else {return "return null;";}}private static String getCaseCode(String code,Class<?> returnClass){if(mappings.containsKey(returnClass)){return "((" + mappings.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName() + "Value()";}return code;}private static boolean hasReturnValue(Class<?> clazz){return clazz != void.class;}private static String toLowerFirstCase(String src){char [] chars = src.toCharArray();chars[0] += 32;return String.valueOf(chars);}}

創建GPClassLoader 類:

public class GPClassLoader extends ClassLoader {private File classPathFile;public GPClassLoader(){String classPath = GPClassLoader.class.getResource("").getPath();this.classPathFile = new File(classPath);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String className = GPClassLoader.class.getPackage().getName() + "." + name;if(classPathFile != null){File classFile = new File(classPathFile,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();}}}return null;} }

創建GPMeipo 類:

public class GPMeipo implements GPInvocationHandler {private Object target;public Object getInstance(Object target) throws Exception{this.target = target;Class<?> clazz = target.getClass();return GPProxy.newProxyInstance(new GPClassLoader(),clazz.getInterfaces(),this);}public 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("我是媒婆,我要給你找對象,現在已經確認你的需求");System.out.println("開始物色");}private void after(){System.out.println("OK的話,準備辦事");} }

到此,手寫JDK 動態代理就完成了。小伙伴們,是不是有多了一個面試用的殺手锏呢?

?

總結

以上是生活随笔為你收集整理的高仿真 JDK Proxy手写实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。