您好,登錄后才能下訂單哦!
這篇文章主要講解了“JDK動態代理的實現方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JDK動態代理的實現方法”吧!
JDK的動態代理的類看不見摸不著,雖然可以看到效果,但是底層到底是怎么做的,為什么要求實現接口呢?
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{ // 判空,判斷 h 對象是否為空,為空就拋出 NullPointerException Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { // 進行包訪問權限、類加載器等權限檢查 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. * 查找或生成指定的代理類 */ Class<?> cl = getProxyClass0(loader, intfs); // 省略若干代碼 }
第一步,嘗試獲取代理類,該代理類可能會被緩存,如果沒有緩存,那么進行生成邏輯.
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { // 數量超過 65535 就拋出異常,665535 這個就不用說了吧 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // 如果代理類已經通過類加載器對給定的接口進行實現了,那么從緩存中返回其副本 // 否則,它將通過ProxyClassFactory創建代理類 return proxyClassCache.get(loader, interfaces); }
最后發現會對生成的代理類進行緩存,有了,就不直接返回,沒有的,還得生成代理類,我們繼續往下走:
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
關鍵點在于 ProxyClassFactory 這個類,從名字也可以猜出來這個類的作用。看看代碼:
/** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names 定義前綴 private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names 原子操作,適用于多線程 private static final AtomicLong nextUniqueNumber = new AtomicLong(); public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ 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"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); // 生產代理類的名字 String proxyName = proxyPkg + proxyClassNamePrefix + num; // 一些驗證、緩存、同步的操作,不是我們研究的重點 /* * Generate the specified proxy class. * 生成特殊的代理類 */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } }
ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);``
這段代碼即為生成動態代理類的關鍵,執行完后會返回該描述該代理類的字節碼數組.隨后程序讀取該字節碼數組,將其轉化為運行時的數據結構-Class對象,作為一個常規類使用.
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); final byte[] var4 = var3.generateClassFile(); // 如果聲明了需要持久化代理類,則進行磁盤寫入. if (saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { try { int var1 = var0.lastIndexOf(46); Path var2; if (var1 > 0) { Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar)); Files.createDirectories(var3); var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); } else { var2 = Paths.get(var0 + ".class"); } Files.write(var2, var4, new OpenOption[0]); return null; } catch (IOException var4x) { throw new InternalError("I/O exception saving generated file: " + var4x); } } }); } return var4; }
這里我們找到了一個關鍵的判斷條件-saveGeneratedFiles,即是否需要將代理類進行持久化.
public class ProxyGeneratorUtils { /** * 把代理類的字節碼寫到硬盤上 * @param path 保存路徑 */ public static void writeProxyClassToHardDisk(String path) { // 獲取代理類的字節碼 byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", Student.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
可以發現,在根目錄下生成了一個 $Proxy0.class 文件,文件內容反編譯后如下:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import proxy.Person; public final class $Proxy0 extends Proxy implements Person { private static Method m1; private static Method m2; private static Method m3; private static Method m0; /** *注意這里是生成代理類的構造方法,方法參數為InvocationHandler類型,看到這,是不是就有點明白 *為何代理對象調用方法都是執行InvocationHandler中的invoke方法,而InvocationHandler又持有一個 *被代理對象的實例,不禁會想難道是....? 沒錯,就是你想的那樣。 * *super(paramInvocationHandler),是調用父類Proxy的構造方法。 *父類持有:protected InvocationHandler h; *Proxy構造方法: * protected Proxy(InvocationHandler h) { * Objects.requireNonNull(h); * this.h = h; * } * */ public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } //這個靜態塊本來是在最后的,我把它拿到前面來,方便描述 static { try { //看看這兒靜態塊兒里面有什么,是不是找到了giveMoney方法。請記住giveMoney通過反射得到的名字m3,其他的先不管 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("proxy.Person").getMethod("giveMoney", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } /** * *這里調用代理對象的giveMoney方法,直接就調用了InvocationHandler中的invoke方法,并把m3傳了進去。 *this.h.invoke(this, m3, null);這里簡單,明了。 *來,再想想,代理對象持有一個InvocationHandler對象,InvocationHandler對象持有一個被代理的對象, *再聯系到InvacationHandler中的invoke方法。嗯,就是這樣。 */ public final void giveMoney() throws { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } //注意,這里為了節省篇幅,省去了toString,hashCode、equals方法的內容。原理和giveMoney方法一毛一樣。 }
jdk 為我們的生成了一個叫 $Proxy0(這個名字后面的0是編號,有多個代理類會一次遞增)的代理類,這個類文件時放在內存中的,我們在創建代理對象時,就是通過反射獲得這個類的構造方法,然后創建的代理實例。通過對這個生成的代理類源碼的查看,我們很容易能看出,動態代理實現的具體過程。
我們可以對 InvocationHandler 看做一個中介類,中介類持有一個被代理對象,在 invoke 方法中調用了被代理對象的相應方法,而生成的代理類中持有中介類,因此,當我們在調用代理類的時候,就是再調用中介類的 invoke 方法,通過反射轉為對被代理對象的調用。
代理類調用自己方法時,通過自身持有的中介類對象來調用中介類對象的 invoke 方法,從而達到代理執行被代理對象的方法。也就是說,動態代理通過中介類實現了具體的代理功能。
生成的代理類:$Proxy0 extends Proxy implements Person,我們看到代理類繼承了 Proxy 類,所以也就決定了 java 動態代理只能對接口進行代理,Java 的繼承機制注定了這些動態代理類們無法實現對 class 的動態代理。
感謝各位的閱讀,以上就是“JDK動態代理的實現方法”的內容了,經過本文的學習后,相信大家對JDK動態代理的實現方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。