- 在使用jdk動態代理的時候,必需要實現InvocationHandler接口;invoke方法中該三個參數分別表示爲: 代理對象、被代理執行的方法、參數
public class JdkInvocationHandler implements InvocationHandler { /** * 被代理類對象 目標代理對象 */ private Object target; public JdkInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(">>>jdk打印訂單日誌開始:proxy:"+proxy.getClass().toString()); Object reuslt = method.invoke(target, args);// java的反射機制執行方法 執行目標對象的方法 System.out.println(">>>jdk打印訂單日誌結束"); return reuslt; } /** * 使用jdk動態代理建立代理類 * * @param <T> * @return */ public <T> T getProxy() { return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } }2.使用jdk動態代理獲取代理類對象(JDK自動生成代理類) $Proxy0.class,使用反編譯工具java
- 建立代理類$Proxy0源代碼文件實現被代理的接口
public final class $Proxy0 extends java.lang.reflect.Proxy implements com.xuyu.service.OrderService {2.使用JavaCompiler技術編譯該$Proxy0文件獲取到$Proxy0.class數據庫
3. 使用ClassLoader將該$Proxy0.class加入到當前JVM內存中設計模式
ClassLoader 顧名思義就是類加載器,ClassLoader 做用:負責將 Class 加載到 JVM 中,審查每一個類由誰加載(父優先的等級加載機制),將 Class字節碼 從新解析成 JVM 統一要求的對象格式
1.自定義MyExtJdkInvocationHandler接口 ——至關於InvocationHandler安全
/** * @title: MyExtJdkInvocationHandler */ public interface MyExtJdkInvocationHandler { /** * @param proxy 代理類 * @param method 目標方法 * @param args 參數 * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }2.寫一個MyJdkInvocationHandler實現MyJdkInvocationHandler接口app
/** * @title: MyJdkInvocationHandler */ public class MyJdkInvocationHandler implements MyExtJdkInvocationHandler { /** * 目標對象 被代理的類 真實訪問的類的對象 */ private Object target; public MyJdkInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("<<<<<<<<<純手寫jdk動態代理日誌開始>>>>>>>>>>"); Object result = method.invoke(target, args);// 使用java的反射執行 System.out.println("<<<<<<<<純手寫jdk動態代理結束>>>>>>>>>>"); return result; } }service層ide
public interface OrderService { public void order() throws Throwable; }/** * @title: OrderServiceImpl */ public class OrderServiceImpl implements OrderService { public void order() { System.out.println("數據庫訂單執行操做"); } }3.對比反編譯$Proxy0.class來寫$Proxy0函數
4.簡單測試工具
public class Test001 { public static void main(String[] args) throws Throwable { OrderService orderService = new $Proxy0(new MyJdkInvocationHandler(new OrderServiceImpl())); orderService.order(); } }5.控制檯輸出結果測試
<<<<<<<<<純手寫jdk動態代理日誌開始>>>>>>>>>> 數據庫訂單執行操做 <<<<<<<<純手寫jdk動態代理結束>>>>>>>>>>
1.先看源碼Proxy怎麼實現的this
public class Proxy implements java.io.Serializable { .... private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); .... private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } //【2】獲取代理類,寫入到到本地文件中.. return proxyClassCache.get(loader, interfaces); } .... private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { private static final String proxyClassNamePrefix = "$Proxy"; private static final AtomicLong nextUniqueNumber = new AtomicLong(); //【3】將源代碼編譯成class文件,幫助咱們初始化,建立class文件 @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } //####代理的包名,可自定義#### String proxyPkg = null; int accessFlags = Modifier.PUBLIC | Modifier.FINAL; for (Class<?> intf : interfaces) { 。。。。 } if (proxyPkg == null) { proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } //####原子類,自增,保證線程安全,原子類計數代理類proxy0,proxy1,proxy2....#### long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; //####建立Java源代碼,轉化爲字節碼文件#### byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { //【4】使用classLoader 加載到內存中,代理類class文件加載到內存#### return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } } .... @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { 。。。。 //【1】建立代理類java源碼文件,寫入到硬盤中.. Class<?> cl = getProxyClass0(loader, intfs); 。。。。1.總結相關要點
1.建立代理類java源碼文件,寫入到硬盤中.. 2. 寫入到到本地文件中.. 3. 將源代碼編譯成class文件 4.使用classLoader 加載到內存中..2.模仿源碼寫代碼
/** * @title: MyProxy */ public class MyProxy { static String rt = "\r\t"; public static Object newProxyInstance(JavaClassLoader javaClassLoader, Class<?> classInfo, MyExtJdkInvocationHandler h) { //1.拼接代理類的源代碼 try { // 1.建立代理類java源碼文件,寫入到硬盤中.. Method[] methods = classInfo.getMethods(); String proxyClass = "package com.xuyu.ext.proxy;" + rt + "import java.lang.reflect.Method;" + rt + "import com.xuyu.ext.proxy.MyExtJdkInvocationHandler;" + rt + "public class $Proxy0 implements " + classInfo.getName() + "{" + rt + "MyExtJdkInvocationHandler h;" + rt + "public $Proxy0(MyExtJdkInvocationHandler h)" + "{" + rt + "this.h= h;" + rt + "}" + getMethodString(methods, classInfo) + rt + "}"; // 2. 寫入到到本地文件中.. String filename = "d:/code/$Proxy0.java"; File f = new File(filename); FileWriter fw = new FileWriter(f); fw.write(proxyClass); fw.flush(); fw.close(); // 3. 將源代碼編譯成class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMgr.getJavaFileObjects(filename); JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units); t.call(); fileMgr.close(); // 4.使用classLoader 加載到內存中.. Class<?> $Proxy0 = javaClassLoader.findClass("$Proxy0"); // 5.指明初始化有參數構造函數 Constructor<?> constructor = $Proxy0.getConstructor(MyExtJdkInvocationHandler.class); Object o = constructor.newInstance(h); return o; } catch (Exception e) { e.printStackTrace(); } return null; } public static String getMethodString(Method[] methods, Class intf) { String proxyMe = ""; for (Method method : methods) { proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt + "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName() + "\",new Class[]{});" + rt + "this.h.invoke(this,md,null);" + rt + "}" + rt; } return proxyMe; } public static void main(String[] args) { newProxyInstance(null, OrderService.class, null); } }3.看源碼怎麼實現ClassLoader類加載器
4.寫出本身的JavaClassLoader 類加載器
public class JavaClassLoader extends ClassLoader { private File classPathFile; public JavaClassLoader(){ String classPath="D:\\code"; this.classPathFile=new File(classPath); } @Override public Class<?> findClass(String name) throws ClassNotFoundException { String className= JavaClassLoader.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(); }finally { if(in!=null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if(out!=null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return null; }5.測試類
/** * @title: Test001 */ public class Test001 { public static void main(String[] args) throws Throwable { OrderService orderService = (OrderService) MyProxy.newProxyInstance(new JavaClassLoader(), OrderService.class, new MyJdkInvocationHandler(new OrderServiceImpl())); orderService.order(); } }6.運行程序生成的$Proxy0.java文件內容
package com.xuyu; import com.xuyu.ext.proxy.MyExtJdkInvocationHandler; import java.lang.reflect.Method; public class $Proxy0 implements com.xuyu.service.OrderService { MyExtJdkInvocationHandler h; public $Proxy0(MyExtJdkInvocationHandler h) { this.h = h; } public void order() throws Throwable { Method md = com.xuyu.service.OrderService.class.getMethod("order", new Class[] { }); this.h.invoke(this, md, null); } }7.控制檯輸出結果
<<<<<<<<<純手寫jdk動態代理日誌開始>>>>>>>>>> 數據庫訂單執行操做 <<<<<<<<純手寫jdk動態代理結束>>>>>>>>>>
版權@須臾之餘https://my.oschina.net/u/3995125
本文參考:
螞蟻課堂:www.mayikt.com