JAVA設計模式-動態代理(Proxy)原始碼分析
在文章:JAVA設計模式-動態代理(Proxy)示例及說明中,為動態代理設計模式舉了一個小小的例子,那麼這篇文章就來分析一下原始碼的實現。
一,Proxy.newProxyInstance方法
1 @CallerSensitive 2 public static Object newProxyInstance(ClassLoader loader, 3 Class<?>[] interfaces, 4 InvocationHandler h)5 throws IllegalArgumentException{ 6 // null檢查,h為null就丟擲NullPointerException 7 Objects.requireNonNull(h); 8 // 將介面類物件陣列clone一份。 9 final Class<?>[] intfs = interfaces.clone(); 10 11 //執行許可權檢查 12 final SecurityManager sm = System.getSecurityManager();13 if (sm != null) { 14 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); 15 } 16 17 /* 18 * Look up or generate the designated proxy class. 19 */ 20 // 查詢或者是生成一個特定的代理類物件 21 Class<?> cl = getProxyClass0(loader, intfs);22 23 /* 24 * Invoke its constructor with the designated invocation handler. 25 */ 26 try { 27 if (sm != null) { 28 checkNewProxyPermission(Reflection.getCallerClass(), cl); 29 } 30 // 是static final 修飾的,原始碼: private static final Class<?>[] constructorParams ={ InvocationHandler.class }; 31 // 從代理類物件中查詢引數為InvocationHandler的構造器 32 final Constructor<?> cons = cl.getConstructor(constructorParams); 33 final InvocationHandler ih = h; 34 // 檢測構造器是否是Public修飾,如果不是則強行轉換為可以訪問的。 35 if (!Modifier.isPublic(cl.getModifiers())) { 36 AccessController.doPrivileged(new PrivilegedAction<Void>() { 37 public Void run() { 38 cons.setAccessible(true); 39 return null; 40 } 41 }); 42 } 43 // 將h作為引數,例項化代理類,返回代理類例項。 44 return cons.newInstance(new Object[]{h}); 45 } catch (IllegalAccessException|InstantiationException e) { 46 throw new InternalError(e.toString(), e); 47 } catch (InvocationTargetException e) { 48 Throwable t = e.getCause(); 49 if (t instanceof RuntimeException) { 50 throw (RuntimeException) t; 51 } else { 52 throw new InternalError(t.toString(), t); 53 } 54 } catch (NoSuchMethodException e) { 55 throw new InternalError(e.toString(), e); 56 } 57 }
newProxyInstance是Proxy的靜態方法,程式碼並不難理解出去許可權關的程式碼外,就剩下兩步:
1,獲取代理類物件(21行)
2,利用反射技術例項化代理類,並返回例項化物件(44行)
接下來分析21行中的getProxyClass0方法
二,Proxy.getProxyClass0方法
1 /** 2 * 生成一個代理類物件, 3 * Generate a proxy class. Must call the checkProxyAccess method 4 * to perform permission checks before calling this. 5 */ 6 private static Class<?> getProxyClass0(ClassLoader loader, 7 Class<?>... interfaces) { 8 // 介面類物件陣列不能大於65535個,否則丟擲異常 9 if (interfaces.length > 65535) { 10 throw new IllegalArgumentException("interface limit exceeded"); 11 } 12 // 從代理類物件快取中,根據類載入器和介面類物件陣列查詢代理類物件, 13 // If the proxy class defined by the given loader implementing 14 // the given interfaces exists, this will simply return the cached copy; 15 // otherwise, it will create the proxy class via the ProxyClassFactory 16 return proxyClassCache.get(loader, interfaces); 17 }
在這個方法中,是直接從一個叫proxyClassCache快取中讀取的,來看一下這個快取的宣告:
//static final private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
這裡涉及到三個類:WeakCache,KeyFactory,ProxyClassFactory,其中後面兩個類都是Proxy類的靜態內部類,從類名可以大概猜測到,keyFactory是用來生產key的,ProxyClassFactory是用來生產代理類物件的,這個稍後會提到。
首先看一下WeakCache類的大概結構:
1 final class WeakCache<K, P, V> { 2 3 private final ReferenceQueue<K> refQueue= new ReferenceQueue<>(); 4 // the key type is Object for supporting null key 5 // key的型別為Object,支援null key,這裡的null key並不是真的可以使用null最為key,而是一個new Objdec()物件例項。ConcurrentHashMap,不允許鍵或值null,而HashMap可以。ConcurrentHashMap是執行緒安全的,HashMap不是。 6 private final ConcurrentMap<Supplier<V>, Boolean> reverseMap= new ConcurrentHashMap<>(); 7 8 private final BiFunction<K, P, ?> subKeyFactory; 9 private final BiFunction<K, P, V> valueFactory; 10 11 //構造方法 12 public WeakCache(BiFunction<K, P, ?> subKeyFactory, 13 BiFunction<K, P, V> valueFactory) { 14 this.subKeyFactory = Objects.requireNonNull(subKeyFactory); 15 this.valueFactory = Objects.requireNonNull(valueFactory); 16 } 17 18 19 public V get(K key, P parameter) { 20 //下面會詳細介紹這個方法 21 } 22 23 ...... 24 }
上面的原始碼中寫明,代理類物件是從proxyClassCache鎮南關讀取的,接下來就分析WeakCache的get方法
三,WeakCache.get方法
1 // key是類載入器,parameter為介面類物件陣列 2 public V get(K key, P parameter) { 3 // 介面類物件陣列null檢查。 4 Objects.requireNonNull(parameter); 5 6 // 刪除過時的條目 7 expungeStaleEntries(); 8 // 生成快取key物件例項,如果key = null,cacheKey = new Object(); 9 Object cacheKey = CacheKey.valueOf(key, refQueue); 10 11 // lazily install the 2nd level valuesMap for the particular cacheKey 12 // 從快取map中讀取指定cacheKey的快取資料valuesMap 13 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); 14 15 if (valuesMap == null) { 16 //如果valuesMap為null,則新增 17 //putIfAbsent方法解釋:如果值存在則返回值,並且不對原來的值做任何更改,如果不存在則新增,並返回null 18 //Absent的意思是缺席,不在 19 ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>()); 20 if (oldValuesMap != null) { 21 valuesMap = oldValuesMap; 22 } 23 } 24 25 // create subKey and retrieve the possible Supplier<V> stored by that 26 // subKey from valuesMap 27 // 獲取subKey,這裡用到了上面提到的Proxy的靜態內部類KeyFactory:subKeyFactory.apply(ket,parameter) 28 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); 29 // 從valuesMap中獲取supplier 30 Supplier<V> supplier = valuesMap.get(subKey); 31 Factory factory = null; 32 33 while (true) { 34 if (supplier != null) { 35 // supplier might be a Factory or a CacheValue<V> instance 36 // 4,從工廠中獲取代理類物件 37 V value = supplier.get(); 38 if (value != null) { 39 // 5,返回 40 return value; 41 } 42 } 43 // else no supplier in cache 44 // or a supplier that returned null (could be a cleared CacheValue 45 // or a Factory that wasn't successful in installing the CacheValue) 46 47 // lazily construct a Factory 48 if (factory == null) { 49 //1,例項化工廠 50 factory = new Factory(key, parameter, subKey, valuesMap); 51 } 52 53 if (supplier == null) { 54 //2,儲存到valuesMap中 55 supplier = valuesMap.putIfAbsent(subKey, factory); 56 if (supplier == null) { 57 // successfully installed Factory 58 // 3,賦值 59 supplier = factory; 60 } 61 // else retry with winning supplier 62 } else { 63 if (valuesMap.replace(subKey, supplier, factory)) { 64 // successfully replaced 65 // cleared CacheEntry / unsuccessful Factory 66 // with our Factory 67 supplier = factory; 68 } else { 69 // retry with current supplier 70 supplier = valuesMap.get(subKey); 71 } 72 } 73 } 74 }
因為程式中Proxy.newProxyInstance是第一次執行,所以while迴圈開始的時候,supplier,valuesMap都是null。在這個前提下,我為程式碼的執行順序做了一個編號,從1-5執行。
可以看到第5步,也就是原始碼的第40行將結果返回,那麼,代理類物件就是在第4步,也就是第37行生成的。而且也可以從第3步,也就是第59行發現supplier就是factory。
那麼接下來,就分析一下Factory.get方法。
四,Factory.get方法
Factory類是WeakCache的內部類。這個類中出去構造方法外,就是get方法了,下面就將這個類的程式碼給出:
1 private final class Factory implements Supplier<V> { 2 3 private final K key; 4 private final P parameter; 5 private final Object subKey; 6 private final ConcurrentMap<Object, Supplier<V>> valuesMap; 7 8 Factory(K key, P parameter, Object subKey, 9 ConcurrentMap<Object, Supplier<V>> valuesMap) { 10 this.key = key; 11 this.parameter = parameter; 12 this.subKey = subKey; 13 this.valuesMap = valuesMap; 14 } 15 16 @Override 17 public synchronized V get() { // serialize access 18 // re-check 19 // 檢查 20 Supplier<V> supplier = valuesMap.get(subKey); 21 if (supplier != this) { 22 // something changed while we were waiting: 23 // might be that we were replaced by a CacheValue 24 // or were removed because of failure -> 25 // return null to signal WeakCache.get() to retry 26 // the loop 27 return null; 28 } 29 // else still us (supplier == this) 30 31 // create new value 32 V value = null; 33 try { 34 // valueFactory就是WeakCache的valueFactory屬性,因為Factory是WeakCache的內部類,所以可以直接訪問WeakCache的valueFactory屬性 35 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); 36 } finally { 37 if (value == null) { // remove us on failure 38 valuesMap.remove(subKey, this); 39 } 40 } 41 // the only path to reach here is with non-null value 42 assert value != null; 43 44 // wrap value with CacheValue (WeakReference) 45 CacheValue<V> cacheValue = new CacheValue<>(value); 46 47 // try replacing us with CacheValue (this should always succeed) 48 if (valuesMap.replace(subKey, this, cacheValue)) { 49 // put also in reverseMap 50 reverseMap.put(cacheValue, Boolean.TRUE); 51 } else { 52 throw new AssertionError("Should not reach here"); 53 } 54 55 // successfully replaced us with new CacheValue -> return the value 56 // wrapped by it 57 return value; 58 } 59 }
關鍵程式碼第35行:valueFactory.apply(key, parameter)
這裡的valueFactory就是Proxy的靜態內部類ProxyClassFactory,上面也提到過,那麼就接著分析ProxyClassFactory的apply方法吧。
五,ProxyClassFactory.apply方法
1 /** 2 * 一個利用給定的類載入器和介面類陣列生成,定義並返回代理類物件的工廠方法 3 * A factory function that generates, defines and returns the proxy class given 4 * the ClassLoader and array of interfaces. 5 */ 6 private static final class ProxyClassFactory 7 implements BiFunction<ClassLoader, Class<?>[], Class<?>> 8 { 9 // prefix for all proxy class names 10 // 所有代理類物件的字首 11 private static final String proxyClassNamePrefix = "$Proxy"; 12 13 // next number to use for generation of unique proxy class names 14 // 用於生成唯一代理類名稱的下一個數字 15 private static final AtomicLong nextUniqueNumber = new AtomicLong(); 16 17 @Override 18 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { 19 20 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); 21 // 22 for (Class<?> intf : interfaces) { 23 /* 24 * Verify that the class loader resolves the name of this 25 * interface to the same Class object. 26 */ 27 Class<?> interfaceClass = null; 28 try { 29 // 載入介面類,獲得介面類的類物件,第二個引數為false表示不進行例項化 30 interfaceClass = Class.forName(intf.getName(), false, loader); 31 } catch (ClassNotFoundException e) { 32 } 33 if (interfaceClass != intf) { 34 throw new IllegalArgumentException( 35 intf + " is not visible from class loader"); 36 } 37 /* 38 * Verify that the Class object actually represents an 39 * interface. 40 */ 41 if (!interfaceClass.isInterface()) { 42 throw new IllegalArgumentException( 43 interfaceClass.getName() + " is not an interface"); 44 } 45 /* 46 * Verify that this interface is not a duplicate. 47 */ 48 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { 49 throw new IllegalArgumentException( 50 "repeated interface: " + interfaceClass.getName()); 51 } 52 } 53 // package to define proxy class in 54 // 代理類的包名 55 String proxyPkg = null; 56 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; 57 58 /* 59 * Record the package of a non-public proxy interface so that the 60 * proxy class will be defined in the same package. Verify that 61 * all non-public proxy interfaces are in the same package. 62 */ 63 for (Class<?> intf : interfaces) { 64 int flags = intf.getModifiers(); 65 if (!Modifier.isPublic(flags)) { 66 accessFlags = Modifier.FINAL; 67 String name = intf.getName(); 68 int n = name.lastIndexOf('.'); 69 String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); 70 if (proxyPkg == null) { 71 proxyPkg = pkg; 72 } else if (!pkg.equals(proxyPkg)) { 73 throw new IllegalArgumentException( 74 "non-public interfaces from different packages"); 75 } 76 } 77 } 78 79 if (proxyPkg == null) { 80 // if no non-public proxy interfaces, use com.sun.proxy package 81 proxyPkg = com.sun.proxy package 82 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; 83 } 84 85 /* 86 * 生成代理類的類名 87 * Choose a name for the proxy class to generate. 88 */ 89 long num = nextUniqueNumber.getAndIncrement(); 90 String proxyName = proxyPkg + proxyClassNamePrefix + num; 91 92 /* 93 * Generate the specified proxy class. 94 */ 95 //生成代理類class檔案 96 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); 97 try { 98 // 返回代理類物件 99 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); 100 } catch (ClassFormatError e) { 101 /* 102 * A ClassFormatError here means that (barring bugs in the 103 * proxy class generation code) there was some other 104 * invalid aspect of the arguments supplied to the proxy 105 * class creation (such as virtual machine limitations 106 * exceeded). 107 */ 108 throw new IllegalArgumentException(e.toString()); 109 } 110 } 111 } 112 }
在程式碼的第96行,生成了代理類的class檔案,並且在99行返回了我們需要的代理類物件。那麼怎麼找到這個生成的代理類class檔案呢?兩個步驟:
1,新增一行程式碼:
//例項化呼叫處理類(編好的故事) MyStoryInvocationHandler handler = new MyStoryInvocationHandler(liHong); //新增這一句是生成代理類的class檔案,前提是你需要在工程根目錄下建立com/sun/proxy目錄 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
2,建立com/sun/proxy目錄:
當這個程式執行完之後就會有$Proxy0.class檔案出現:
六,反編譯$Proxy0.class
1 package com.sun.proxy; 2 3 import com.zcz.proxyTest.testtwo.Singer; 4 import java.lang.reflect.InvocationHandler; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Proxy; 7 import java.lang.reflect.UndeclaredThrowableException; 8 9 //繼承了Proxy類,實現了Singer介面 10 public final class $Proxy0 extends Proxy implements Singer{ 11 private static Method m1; 12 private static Method m4; 13 private static Method m2; 14 private static Method m3; 15 private static Method m0; 16 17 //構造方法,直接呼叫了父類,也就是Proxy的構造方法,引數paramInvocationHandler就是我們的MyStoryInvocationHandler例項化物件handler 18 public $Proxy0(InvocationHandler paramInvocationHandler)throws { 19 super(paramInvocationHandler); 20 } 21 22 public final boolean equals(Object paramObject) 23 throws { 24 try 25 { 26 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); 27 } 28 catch (Error|RuntimeException localError) 29 { 30 throw localError; 31 } 32 catch (Throwable localThrowable) 33 { 34 throw new UndeclaredThrowableException(localThrowable); 35 } 36 } 37 38 //實現了sayGoodBye 39 public final void sayGoodBye(String paramString) 40 throws { 41 try 42 { 43 // 這裡的h就是我們的MyStoryInvocationHandler例項化物件handler,原因在下方解釋。 44 // 這裡直接呼叫了MyStoryInvocationHandler的invoke方法 45 this.h.invoke(this, m4, new Object[] { paramString }); 46 return; 47 } 48 catch (Error|RuntimeException localError) 49 { 50 throw localError; 51 } 52 catch (Throwable localThrowable) 53 { 54 throw new UndeclaredThrowableException(localThrowable); 55 } 56 } 57 58 public final String toString() 59 throws 60 { 61 try 62 { 63 return (String)this.h.invoke(this, m2, null); 64 } 65 catch (Error|RuntimeException localError) 66 { 67 throw localError; 68 } 69 catch (Throwable localThrowable) 70 { 71 throw new UndeclaredThrowableException(localThrowable); 72 } 73 } 74 //實現了orderSong方法 75 public final void orderSong(String paramString) 76 throws 77 { 78 try 79 { 80 // 這裡的h就是我們的MyStoryInvocationHandler例項化物件handler,原因在下方解釋。 81 // 這裡直接呼叫了MyStoryInvocationHandler的invoke方法 82 this.h.invoke(this, m3, new Object[] { paramString }); 83 return; 84 } 85 catch (Error|RuntimeException localError) 86 { 87 throw localError; 88 } 89 catch (Throwable localThrowable) 90 { 91 throw new UndeclaredThrowableException(localThrowable); 92 } 93