原文鏈接: JDK動(dòng)態(tài)代理實(shí)現(xiàn)機(jī)制 轉(zhuǎn)載請(qǐng)注明出處!
===========================================
本文只對(duì)JDK動(dòng)態(tài)代理的底層實(shí)現(xiàn)進(jìn)行分析,如需了解代理模式和動(dòng)態(tài)代理的使用請(qǐng)移步:設(shè)計(jì)模式—代理模式 動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式(JDK/Cglib)
在讀代碼之前先清楚兩個(gè)概念:
1、Class類存儲(chǔ)的是類的所有信息,包括類的所有方法、屬性、實(shí)現(xiàn)接口等。每個(gè)類對(duì)應(yīng)一個(gè)Class對(duì)象(單例),Class對(duì)象是由classLoader加載出來的,使用雙親委派模型來保證class只會(huì)被加載一次。
2、classLoader在加載類的時(shí)候不管class文件是從哪里來的,無論是從.class文件、網(wǎng)絡(luò)、數(shù)據(jù)庫(kù)類加載器都不關(guān)心。他只關(guān)心給他的class二進(jìn)制流是不是能夠通過校驗(yàn)。
說明:以下測(cè)試代碼和 動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式(JDK/Cglib)相同
使用JDK動(dòng)態(tài)代理需要實(shí)現(xiàn)InvocationHandler接口,同時(shí)實(shí)現(xiàn)invoke()方法。
package com.zpj.proxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * Created by Perkins on 2017/4/2. */public class JDKProxy implements InvocationHandler { private Object person; public Object getInstance(Object person) { this.person = person; return Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("doSomething---------start"); method.invoke(person, args); System.out.println("doSomething---------end"); return null; } }
測(cè)試代碼如下:
package com.zpj.proxy.jdk;/** * Created by Perkins on 2017/4/2. */public class Run { public static void main(String[] args) { Person person = (Person) new JDKProxy().getInstance(new MrLi()); person.doWork(); } }
運(yùn)行的時(shí)候在person處打斷點(diǎn)可看到person的類名為$Proxy0而不是Person或者M(jìn)rLi,則說明該返回對(duì)象是Person的實(shí)現(xiàn)類。
我們添加如下代碼把person的class中的方法打印出來
package com.zpj.proxy.jdk;/** * Created by Perkins on 2017/4/2. */import java.lang.reflect.Method;public class Run { private Method method; public static void main(String[] args) { Person person = (Person) new JDKProxy().getInstance(new MrLi()); Method [] methods = person.getClass().getMethods(); for(int i =0; i<methods.length;i++){ System.out.println(methods[i].getName()); } person.doWork(); } }
結(jié)果如下,很明顯紅框中的方法不屬于Person也不屬于Object中的方法。這更進(jìn)一步說明返回的person并不是Person的實(shí)例。
下面就進(jìn)入底層代碼對(duì)JDK動(dòng)態(tài)代理進(jìn)行解析。
這里直接對(duì)Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);進(jìn)行分析。
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException{ if (h == null) { //驗(yàn)證InvocationHandler不允許為null throw new NullPointerException(); } /* * Look up or generate the designated proxy class. */ //調(diào)用getProxyClass()獲取Class實(shí)例,該實(shí)例便是返回的代理Person的實(shí)例,此方法為重點(diǎn)?。?! Class cl = getProxyClass(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { //利用反射機(jī)制從Class中取出構(gòu)造器創(chuàng)建對(duì)象 Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }
在上面方法中調(diào)用public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)throws IllegalArgumentException獲取了Class實(shí)例,下面進(jìn)入該方法進(jìn)行分析。
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { if (interfaces.length > 65535) { //驗(yàn)證接口數(shù)量不允許超過65535 throw new IllegalArgumentException("interface limit exceeded"); } //************開始對(duì)interface進(jìn)行循環(huán)驗(yàn)證,驗(yàn)證通過則加入interfaceNames中*************************** Class proxyClass = null; /* collect interface names to use as key for proxy class cache */ String[] interfaceNames = new String[interfaces.length]; Set interfaceSet = new HashSet(); // for detecting duplicates for (int i = 0; i < interfaces.length; i++) {//循環(huán)對(duì)所有接口進(jìn)行操作 /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ String interfaceName = interfaces[i].getName(); Class interfaceClass = null; try { //根據(jù)名稱獲取接口的Class interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) { throw new IllegalArgumentException(interfaces[i] + " 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.contains(interfaceClass)) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } interfaceSet.add(interfaceClass); interfaceNames[i] = interfaceName; }//************結(jié)束對(duì)interface進(jìn)行循環(huán)驗(yàn)證,存儲(chǔ)于interfaceNames中*************************** /* * Using string representations of the proxy interfaces as * keys in the proxy class cache (instead of their Class * objects) is sufficient because we require the proxy * interfaces to be resolvable by name through the supplied * class loader, and it has the advantage that using a string * representation of a class makes for an implicit weak * reference to the class. */ Object key = Arrays.asList(interfaceNames); /* * Find or create the proxy class cache for the class loader. */ Map cache; synchronized (loaderToCache) { cache = (Map) loaderToCache.get(loader); if (cache == null) { cache = new HashMap(); loaderToCache.put(loader, cache); } /* * This mapping will remain valid for the duration of this * method, without further synchronization, because the mapping * will only be removed if the class loader becomes unreachable. */ } /* * Look up the list of interfaces in the proxy class cache using * the key. This lookup will result in one of three possible * kinds of values: * null, if there is currently no proxy class for the list of * interfaces in the class loader, * the pendingGenerationMarker object, if a proxy class for the * list of interfaces is currently being generated, * or a weak reference to a Class object, if a proxy class for * the list of interfaces has already been generated. */ synchronized (cache) { /* * Note that we need not worry about reaping the cache for * entries with cleared weak references because if a proxy class * has been garbage collected, its class loader will have been * garbage collected as well, so the entire cache will be reaped * from the loaderToCache map. */ do { Object value = cache.get(key); if (value instanceof Reference) { proxyClass = (Class) ((Reference) value).get(); } if (proxyClass != null) { // proxy class already generated: return it return proxyClass; } else if (value == pendingGenerationMarker) { // proxy class being generated: wait for it try { cache.wait(); } catch (InterruptedException e) { /* * The class generation that we are waiting for should * take a small, bounded time, so we can safely ignore * thread interrupts here. */ } continue; } else { /* * No proxy class for this list of interfaces has been * generated or is being generated, so we will go and * generate it now. Mark it as pending generation. */ cache.put(key, pendingGenerationMarker); break; } } while (true); } try { String proxyPkg = null; // package to define proxy class in /* * 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. */ //尋找到package的包路徑,為構(gòu)建代理類做準(zhǔn)備。同時(shí)要保證所有的非public代理接口在相同的包中 for (int i = 0; i < interfaces.length; i++) { int flags = interfaces[i].getModifiers(); if (!Modifier.isPublic(flags)) { String name = interfaces[i].getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPk
http://www.cnblogs.com/PerkinsZhu/p/6658066.html