- title: Jdk動(dòng)態(tài)代理原理解析
- tags:代理
- categories:筆記
- date: 2017-06-14 9:48:05
動(dòng)態(tài)代理這個(gè)知識點(diǎn),也是我們開發(fā)過程中非常容易遇到。特別的是在一些框架中,為了滿足軟件開發(fā)的開閉原則,以及增強(qiáng)框架自身的靈活拓展功能。在底層就會為那些特定的目標(biāo)類或者接口實(shí)現(xiàn)類進(jìn)行渲染與自定義功能操作。就如spring框架中的aop,底層也是通過動(dòng)態(tài)代理來實(shí)現(xiàn)的,所以,就像看看jdk自身的動(dòng)態(tài)代理是如
何實(shí)現(xiàn)的,整個(gè)過程是如何流動(dòng)的。

什么是動(dòng)態(tài)代理,有什么優(yōu)勢?
動(dòng)態(tài),指的是代理類實(shí)在程序運(yùn)行時(shí)創(chuàng)建的,而不是在程序運(yùn)行前手動(dòng)編碼來定義代理類的。這些動(dòng)態(tài)代理類是在運(yùn)行時(shí)候根據(jù)我們在JAVA代碼中
的“指示”動(dòng)態(tài)生成的。相比于靜態(tài)代理,動(dòng)態(tài)代理的優(yōu)勢在于可以很方便的對代理類的函數(shù)進(jìn)行統(tǒng)一處理,而不用修改每個(gè)代理類的函數(shù)。
有點(diǎn)類似于AOP的動(dòng)態(tài)切面編程,為程序以供一些基礎(chǔ)公用的實(shí)現(xiàn),而不用分別針對每個(gè)實(shí)際類的方法進(jìn)行前后環(huán)繞處理。有很多框架都是基于反射和動(dòng)態(tài)代理基礎(chǔ)上進(jìn)行框架能力擴(kuò)展,并實(shí)現(xiàn)JAVASE平臺上基礎(chǔ)接口或者繼承類進(jìn)而實(shí)現(xiàn)與JAVASE平臺的耦合。
動(dòng)態(tài)代理使用場景,有哪些類別?
動(dòng)態(tài)代理的使用方式呢,主要就是分為兩種:一種是基于接口的代理;另一種則是基于類的代理?;诮涌诘拇?,就是jdk自帶的動(dòng)態(tài)代理規(guī)則的實(shí)現(xiàn)方式,后者則是基于一些字節(jié)類增強(qiáng)的類代理,如cglib,javassist等。
但是,動(dòng)態(tài)代理實(shí)際的操作對象,都是在目標(biāo)類的基礎(chǔ)上,生成一個(gè)具有代理目的,增強(qiáng)功能的新的代理proxy字節(jié)碼類。都是在復(fù)合class字節(jié)碼的規(guī)范下,對class字節(jié)文件內(nèi)的內(nèi)容進(jìn)行操作,最后將生成的字節(jié)類對應(yīng)的代理類,通過類加載器加載到JVM中,進(jìn)行使用。
● JDK自帶的基于接口Interface的代理
● 三方CGLIB,JAVASSIST等字節(jié)碼處理的類庫,是基于Class類來實(shí)現(xiàn)代理
動(dòng)態(tài)代理原理分析
說完了,動(dòng)態(tài)代理的概念和大致的種類劃分,現(xiàn)在就基于jdk自己的基于接口的動(dòng)態(tài)代理來進(jìn)行分析,通過實(shí)際的代碼樣例,逐步分析每個(gè)過程,到最后目標(biāo)類的擴(kuò)展完成。
動(dòng)態(tài)代理使用
【1】jdk代理代碼樣例:
結(jié)合最上面的,代理結(jié)構(gòu)圖,可以知道。jdk代理最主要的就是三個(gè)類:目標(biāo)接口,目標(biāo)類(實(shí)現(xiàn)了目標(biāo)接口),擴(kuò)展處理器InvocationHandler類。
//目標(biāo)接口,對應(yīng)ITraget
public interface Subject {
void hello(String str);
}
//目標(biāo)類,對應(yīng)Target
public class RealSubject implements Subject{
public void hello(String str) {
System.out.println("hello" + str);
}
}
//InvocationHandler增強(qiáng)處理器接口實(shí)現(xiàn)類
//方法調(diào)用句柄invoke方法內(nèi)部就是代理類的擴(kuò)展點(diǎn)
public class DynamicProxy implements InvocationHandler{
private Object target;//反射代理目標(biāo)類(被代理,解耦的目標(biāo)類)
//可以通過構(gòu)造器動(dòng)態(tài)設(shè)置被代理目標(biāo)類,以便于調(diào)用指定方法
public DynamicProxy(Object subject){
this.target = subject;
}
//代理過程中的擴(kuò)展點(diǎn)
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("brfore call specific method >>" + method.getName());
Object result = method.invoke(target, args);//MethodAccessor.invoke()
System.out.println("after call specific method>>" + method.getName());
return result;
}
}
【2】客戶端調(diào)用:
在定義完動(dòng)態(tài)代理幾種基本類型之后,就可以在客戶端中進(jìn)行代理實(shí)現(xiàn)。為了更清楚說明這個(gè)動(dòng)態(tài)代理的過程,可以分為以下兩種情形來進(jìn)行使用分析:
(1)冗余型:過程清新,代碼冗余
@Test
public void t() throws Exception{
Subject realSubject = new RealSubject();
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//1.0 獲取代理類的類對象,主要設(shè)置相同的ClassLoader去加載目標(biāo)類實(shí)現(xiàn)的接口Subject類
Class<?> proxyClass = Proxy.getProxyClass(Client.class.getClassLoader(), new Class[]{Subject.class});
//2.0 得到代理類后,就可以通過代理類的處理器句柄來得到構(gòu)造器
final Constructor<?> con = proxyClass.getConstructor(InvocationHandler.class);
//3.0 獲取具體執(zhí)行方法的句柄處理器,目的通過構(gòu)造器傳入被代理目標(biāo)類對象,注入到代理類處理器句柄中進(jìn)行代理調(diào)用
final InvocationHandler handler = new DynamicProxy(realSubject);
//4.0 通過構(gòu)造器創(chuàng)建代理類對象
Subject subject = (Subject)con.newInstance(handler);
//5.0 最后調(diào)用方法
subject.hello("proxy");
(2)簡潔型:過程不是很清新,但是代碼簡潔
這種使用方式,也是我們經(jīng)常看到的。
//設(shè)置生成代理類文件到本地
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
Subject subject2 = (Subject)Proxy.newProxyInstance(Client.class.getClassLoader(),
new Class[]{Subject.class}, new DynamicProxy(new RealSubject()));
//調(diào)用代理類方法
subject2.hello("proxy");
【3】使用分析:
通過上述代碼可以知道,jdk中的接口代理有幾個(gè)重要的點(diǎn):
- 最后方法的調(diào)用一定是聲明在接口的方法。只是具體動(dòng)態(tài)方法調(diào)用的時(shí)候,執(zhí)行的是接口實(shí)現(xiàn)子類中方法。
- 方法的調(diào)用點(diǎn)一定是在InvocationHandler接口或者其子類的invoke方法中,并且該接口中存在目標(biāo)類的對象(依賴),這里也是代理類的拓展點(diǎn)。
- 方法調(diào)用的對象,一定是通過構(gòu)造器形式來創(chuàng)建出來的。
在按照規(guī)定,正確使用了proxy動(dòng)態(tài)代理之后,會思考:為什么jdk的代理一定是基于接口實(shí)現(xiàn)的呢?
這里,可以先說說分析后的想法:
因?yàn)樵趧?dòng)態(tài)代理過程中,會生成對應(yīng)的代理類形如$Proxy0,$Proxy1....</font>這樣的匿名類,這些類都是繼承java.lang.reflect.Proxy類和實(shí)現(xiàn)了我們傳入
的接口,形如:public final class $Proxy0 extends Proxy implements Subject .所以,通過Proxy.newProxyInstance方法返回的就是這個(gè)匿名類的實(shí)例。通常就通過強(qiáng)制轉(zhuǎn)換成指定接口,最后就可以調(diào)用方法了。【java中不能多重繼承,當(dāng)代理匿名類實(shí)現(xiàn)了jdk中的Proxy.class類的時(shí)候,就只能通過實(shí)現(xiàn)目標(biāo)接口的方式來實(shí)現(xiàn)拓展】
(Subject)Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{Subject.class}, new DynamicProxy(new RealSubject()))
若是強(qiáng)制轉(zhuǎn)換成接口實(shí)現(xiàn)子類,形如:
(RealSubject)Proxy.newProxyInstance(Client.class.getClassLoader(),
new Class[]{Subject.class}, new DynamicProxy(new RealSubject()))
就會報(bào)如下錯(cuò)誤:
java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to proxy.RealSubject。
代理流程分析
就基于上述使用的樣例中的動(dòng)態(tài)代理的代碼,對每個(gè)步驟的過程進(jìn)行分析??纯?,每個(gè)步驟內(nèi)部是如何運(yùn)行的。
因?yàn)?,整個(gè)jdk動(dòng)態(tài)代理過程都與java.lang.reflect.Proxy類有關(guān),就先看看該類中一些重要分屬性字段:

生成代理類
然后,整體看看創(chuàng)建代理對象newProxyInstance方法源代碼:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
結(jié)合上述代碼,來講講幾個(gè)重要的階段:
【1】傳入目標(biāo)接口類和處理器InvocationHandler實(shí)現(xiàn)類:
可以看到客戶端調(diào)用newProxyInstance方法,傳入了類加載器,接口類還有句柄處理器Invocationhandler實(shí)現(xiàn)類。傳入的這些類都是為下面步驟做基礎(chǔ)的。
(Subject)Proxy.newProxyInstance(Client.class.getClassLoader(),
new Class[]{Subject.class}, new DynamicProxy(new RealSubject()))
【2】根據(jù)類加載器和目標(biāo)接口類獲取代理類Class對象:
這部分也是代理類的核心,因?yàn)檫@方法里面包含了代理類的動(dòng)態(tài)創(chuàng)建過程。會生成一個(gè)形如$Proxy0...之類的動(dòng)態(tài)代理類,然后JVM會加載這些字節(jié)類,得到對應(yīng)的Class對象,進(jìn)行緩存。下面看看過程:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
Class<?> proxyClass = null;
/* collect interface names to use as key for proxy class cache */
String[] interfaceNames = new String[interfaces.length];
// for detecting duplicates
Set<Class<?>> interfaceSet = new HashSet<>();
for (int i = 0; i < interfaces.length; i++) {
/*
* 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 {
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");
}
....
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceName;
}
List<String> key = Arrays.asList(interfaceNames);
/*
* Find or create the proxy class cache for the class loader.
*/
Map<List<String>, Object> cache;
synchronized (loaderToCache) {
cache = loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap<>();
loaderToCache.put(loader, cache);
}
}
synchronized (cache) {
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) {
}
continue;
} else {
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
try {
String proxyPkg = null; // package to define proxy class in
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) {
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;
....
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
} finally {
....
}
return proxyClass;
}
根據(jù)源代碼來逐步分析分析:(最重要的就是生成代理類字節(jié)碼$Proxy0...$Proxyn,還有就是進(jìn)行緩存)
(1)首先創(chuàng)建一個(gè)字符串?dāng)?shù)組,用于存放入?yún)nterfaces中的所有不同接口的類型。便于后面使用全限定類名字符串創(chuàng)建類實(shí)例和緩存處理。
String[] interfaceNames = new String[interfaces.length],先創(chuàng)建容器存放類字符串名。
(2)循環(huán)傳入的多參接口類型:并通過Class.forName()方法反射拿到字面量類對應(yīng)的Class<?>對象,并對該對象進(jìn)行同名Class是否相同校驗(yàn),判斷該類是否是接口校驗(yàn),校驗(yàn)傳入的接口參數(shù)是否有重復(fù)等等,最后將校驗(yàn)過后有效的Class對象的類名給存放到(1)中的interfaceNames變量中。
(3) 在Proxy類中有個(gè)loadToCache變量,是用來保存JVM中根據(jù)指定ClassLoader加載的所有Class類的緩存信息。類型變量是
Map<ClassLoader,Map<List<String>,Object>>
因?yàn)榕袛嗍欠袷峭粋€(gè)類,需要與將類加載器與類一起判定。
(4)往下,就是通過這些類名,結(jié)合類加載器來創(chuàng)建或者查詢指定的Class代理類對象?,F(xiàn)將interfaceNames字符數(shù)組中類字符串轉(zhuǎn)化為List<String>,
List<String> key = Arrays.asList(interfaceNames);
然后創(chuàng)建一個(gè) Map<List<String>, Object>類型的cache變量,用于存放已經(jīng)校驗(yàn)后加載過的類字符串,形如:[java.lang.Class, java.util.List, java.util.Map]=java.lang.Object@59b55efc 樣子的代理類,
其中Object主要是用來當(dāng)做信號量也就是 互斥鎖的。Object位置的值根據(jù)不同情況分為以下幾種:
【 Object value = cache.get(key)】
4.1. 當(dāng)value instanceof java.lang.ref.Reference : 說明根據(jù)傳入的interfaces接口類,在當(dāng)前緩存中能找到對應(yīng)的Class對象,并根據(jù)這個(gè)key返回Class.
4.2. 當(dāng)value==pendingGenerationMarker: 說明,JVM正在生成或者加載指定key值類字符串代表的Class對象,這時(shí)候不能重新生成代理類,需要等待。cache.wait(),等待當(dāng)其他創(chuàng)建代理類線程將代理類創(chuàng)建好后,notify提醒并恢復(fù)線程。
4.3. 當(dāng)代理類proxyClass==null 并且value!=pendingGenerationMarker:這時(shí)候說明,需要根據(jù)類字符串創(chuàng)建Class并加載類了。
(5) 通過一個(gè)方法內(nèi)的代碼塊,創(chuàng)建代理類$Proxy類字節(jié)碼,并將生成的類信息加載到cache緩存中:
5.1.通過ProxyGenerator.generateProxyClass( proxyName, interfaces)方法,按照Class文件標(biāo)準(zhǔn)格式結(jié)合JNI的defineClass0()方法生成Proxy匿名代理類。
5.2 .將生成的代理類保存到proxyClasses變量中,用于為isProxyClass()方法服務(wù)。
5.3.最后,將生成的匿名代理字節(jié)類$Proxy0,1...等信息保存到緩沖中: cache.put(key, new WeakReference<Class<?>>(proxyClass)),創(chuàng)建了一個(gè)弱引用的代理類。
5.4.返回該代理類對應(yīng)的Class對象。
那么生成的動(dòng)態(tài)代理類是什么樣呢?
可以在代碼中設(shè)置:System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"),會在項(xiàng)目根目錄生成class字節(jié)文件,通過反編譯可以看到:
public final class $Proxy0 extends Proxy implements Subject
{
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
//這就是為什么需要將InvocationHandler.class出入構(gòu)造器來查找構(gòu)造器實(shí)例的原理
public $Proxy0(InvocationHandler paramInvocationHandler) throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
//這個(gè)是我們要調(diào)用的目標(biāo)類中方法
public final void hello(String paramString)
throws
{
try
{
//實(shí)際上可以看到,是調(diào)用了我們自定義的InvocationHandler接口實(shí)現(xiàn)類的invoke方法。
// m3這個(gè)Method對象,是通過反射獲取的
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
//靜態(tài)代碼塊,用于通過反射來初始化四個(gè)方法屬性
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("proxy.Subject").getMethod("hello", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
【3】根據(jù)得到的代理類Class對象,通過反射獲取指定構(gòu)造器類對象,且并未創(chuàng)建對象:
Constructor<?> cons = proxyClass.getConstructor(new Class[]{InvocationHandler.class})
為什么要傳入一個(gè)InvocationHandler.class類型的類對象到構(gòu)造器呢?去那里找這個(gè)構(gòu)造器呢?
其實(shí)就是在獲取得到的代理類$Proxy0.class字節(jié)碼中,通過反編譯就可以看到:
該類有一個(gè)構(gòu)造器,且其構(gòu)造器參數(shù)就是InvocationHandler。如下:
public $Proxy0(InvocationHandler paramInvocationHandler) throws
{
super(paramInvocationHandler);
}
//其實(shí),也是繼承了Proxy父類的構(gòu)造器形式。
protected Proxy(InvocationHandler h) {
doNewInstanceCheck();
this.h = h;
}
那么,Class.class中的getConstructor(Class<?>... parameterTypes)內(nèi)部是如何實(shí)現(xiàn)的呢,通過以下幾步:
調(diào)用Class類中的方法:getConstructor0(parameterTypes, Member.PUBLIC)
A. privateGetDeclaredConstructors()獲取所有Public修飾公有的構(gòu)造器,返回構(gòu)造器數(shù)組
B. 根據(jù)構(gòu)造器類型,遍歷構(gòu)造器數(shù)組并進(jìn)行參數(shù)對比,找到代理類中所有構(gòu)造器中參數(shù)是parameterTypes的構(gòu)造器。
C. 找到匹配的構(gòu)造器constructor后,調(diào)用ReflectionFactory工廠的copyConstructor(constructor)復(fù)制構(gòu)造器。
D. 調(diào)用ReflectAccess類的copyConstructor(Constructor<T> args)方法。
E. 最后還是要調(diào)用Constructor.class中的copy()方法,來對找到的構(gòu)造器進(jìn)行復(fù)制。完成屬性root和constructorAccessor屬性的賦值。返回復(fù)制好的新的構(gòu)造器對象。
【4】根據(jù)得到的構(gòu)造器類創(chuàng)建代理類實(shí)例:newInstance(cons,InvocationHandler)</font>
調(diào)用入?yún)?gòu)造器的newInstance方法,通過反射創(chuàng)建代理類的對象。
final InvocationHandler ih = h;
cons.newInstance(new Object[] {h} );
那么,構(gòu)造器創(chuàng)建實(shí)例內(nèi)部是如何運(yùn)行的:
調(diào)用Constructor.class的newInstance方法:Constructor.newInstance(Object ... initargs):
A. 先判斷Constructor共用的constructorAccessor屬性是否為null?
B. 若為null,則調(diào)用acquireConstructorAccessor()方法獲取一個(gè)ConstructorAccessor接口實(shí)例;若不為空,則調(diào)用constructorAccessor.newInstance()方法。調(diào)用acquireConstructorAccessor()方法:目的為了獲取共用的ConstructorAccessor實(shí)現(xiàn)類。
A. 判斷夫?qū)傩詒oot.getConstructorAccessor()是否為null?
B. 因?yàn)闃?gòu)造器訪問器是共用的。所以若是父類中有,那么直接返回。
C.若是父類的構(gòu)造器訪問器為null,則需要調(diào)用ReflectionFactory.newConstructorAccessor(this)方法。
D. 先判斷ReflectionFactory中的noInflation屬性是否為true,默認(rèn)是false。若是noInflation==true或者則調(diào)用MethodAccessorGenerator的generateConstructor()方法,生成一個(gè)類名為:“sun.reflect.GeneratedConstructorAccessor”+Num形式的標(biāo)準(zhǔn)類字節(jié),并使用DelegatingClassLoader來加載這個(gè)類,并將該GeneratedConstructorAccessorXXX實(shí)例對象返回。
E. 若是noInfation為false,且NativeConstructorAccessorImpl類中的表示該JNI本地方法newInstance0被調(diào)用次數(shù)小于15次時(shí)候,就會返回DelegatingConstructorAccessorImpl代理類,并設(shè)置該代理類中delegate代理屬性字段為NativeConstructorAccessorImpl的實(shí)例對象。
F. 當(dāng)獲取到了ConstructorAccessor實(shí)例對象后,就調(diào)用該對象的newInstance(initargs)方法:
在這個(gè)最后調(diào)用創(chuàng)建實(shí)例的方法中,若是多次調(diào)用這個(gè)方法,實(shí)際上是通過代理調(diào)用NativeConstructorAccessorImpl.newInstance0()方法,若是該方法調(diào)用次數(shù)大于15次,就會 如D步驟,生成一個(gè)GeneratedConstructorAccessorXXX類實(shí)例對象返回,且調(diào)用該實(shí)例對象的newInstance(initargs)方法。得到ConstrcutorAccessor接口實(shí)例對象,調(diào)用該對象的newInstance(initargs)方法。
代理類方法調(diào)用
當(dāng)通過上面的流程運(yùn)行過后,就能生成并返回一個(gè)動(dòng)態(tài)代理類<font color="red">$Proxy0</font>的實(shí)例對象。該代理類內(nèi)部的源代碼通過上述步驟中,也能看到了。剩下的,就是調(diào)用返回的目標(biāo)接口實(shí)現(xiàn)類:$Proxy0類的對象調(diào)用接口中聲明中方法,進(jìn)行功能增強(qiáng)了:
Subject subject2 = (Subject)Proxy.newProxyInstance(Client.class.getClassLoader(),
new Class[]{Subject.class}, new DynamicProxy(new RealSubject()));
//目標(biāo)類的代理類方法調(diào)用
subject2.hello("dynamic proxoy");
那么,這個(gè)調(diào)用的方法實(shí)際上如何運(yùn)行的呢?結(jié)合$Proxy0類的源代碼來說明:
【1】首先,在動(dòng)態(tài)代理類$Proxy0中的靜態(tài)代碼塊中,通過反射首先獲得被代理目標(biāo)類中的調(diào)用方法和方法參數(shù)。因?yàn)樽罱K的方法調(diào)用,還是要通過該反射得到的Method對象進(jìn)行調(diào)用的。</font>
private static Method m3;
m3 = Class.forName("proxy.Subject").getMethod("hello", new Class[] { Class.forName("java.lang.String") });
可以看到,是通過反射得到代理目標(biāo)類中的拓展點(diǎn)方法的Method對象。
【2】調(diào)用擴(kuò)展的方法,內(nèi)部實(shí)際是調(diào)用調(diào)用處理器InvocationHandler實(shí)現(xiàn)類的invoke方法。這就是為什么我們要自定義InvocationHandler實(shí)現(xiàn)類,并重寫該接口的invoke方法。并傳入代理目標(biāo)類this,被擴(kuò)展方法m3,方法參數(shù)等等。
//這個(gè)是我們要調(diào)用的目標(biāo)類中方法
public final void hello(String paramString)
throws
{
try
{
//實(shí)際上可以看到,是調(diào)用了我們自定義的InvocationHandler接口實(shí)現(xiàn)類的invoke方法。
// m3這個(gè)Method對象,是通過反射獲取的
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
可以看到,當(dāng)我們在調(diào)用代理返回的代理對象的hello方法的時(shí)候,其實(shí)底層調(diào)用的是我們自定義InvaotionHandler實(shí)現(xiàn)類的invoke方法。其中,變量this.h是那里來的呢?其實(shí),就是通過extends Proxy 繼承java.lang.reflect.Proxy類中的,h的類型就是InvocationHandler,如下:
//java.lang.reflect.Proxy.class
public class Proxy implements java.io.Serializable {
.....
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
}
可以看到,該字段是protected類型的,就是子類可以訪問并使用到的。
【3】最后就是,自定義InvocationHandler內(nèi)部invoke方法調(diào)用:
我們可控的調(diào)用鏈就是到自定義InvocationHandler實(shí)現(xiàn)類的invoke方法就終止了,看看我們定義的實(shí)現(xiàn)類invoke實(shí)現(xiàn):
public class DynamicProxy implements InvocationHandler{
private Object target;//反射代理目標(biāo)類(被代理,解耦的目標(biāo)類)
//可以通過構(gòu)造器動(dòng)態(tài)設(shè)置被代理目標(biāo)類,以便于調(diào)用指定方法
public DynamicProxy(Object subject){
this.target = subject;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("brfore call specific method >>" + method.getName());
Object result = method.invoke(target, args);//MethodAccessor.invoke()
System.out.println("after call specific method>>" + method.getName());
return result;
}
}
可以看到,通過第二步,通過反射得到的Method m3對象,傳入invoke方法內(nèi),最后就是調(diào)用的是m3.invoke方法。關(guān)于反射方法的invoke方法的內(nèi)部實(shí)現(xiàn),可以參考:反射代理類加載器的潛在內(nèi)存使用問題.
總結(jié)來說,就是通過Method.copy方法拷貝一個(gè)相同的方法,并調(diào)用所有方法共享的MethodAccessor對象來實(shí)際調(diào)用。
所以,Proxy代理類的執(zhí)行過程:
Proxy.newInstance() --> Constructor.copy() ----Constructor.newInstance() ----->
$Proxy代理字節(jié)類生成 ---> Method.copy()-----> $Proxy.invoke()(目標(biāo)接口方法調(diào)用)
---> InvocationHandler.invoke() ---> Method.invoke()
同時(shí)我們一定要記住,通過 Proxy.newProxyInstance 創(chuàng)建的代理對象是在jvm運(yùn)行時(shí)動(dòng)態(tài)生成的一個(gè)對象,它并不是我們的InvocationHandler類型,也不是我們定義的那組接口的類型,而是在運(yùn)行是動(dòng)態(tài)生成的一個(gè)對象,并且命名方式都是這樣的形式,以$開頭,proxy為中,最后一個(gè)數(shù)字表示對象的標(biāo)號。
【-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 參數(shù)可以在項(xiàng)目根目錄下的com/sun/proxy/目錄下生成$Proxy0,1....代理類字節(jié)碼文件?!?/p>
另外說說代理有關(guān)的Inflation機(jī)制:
若是想測試看看Inflation機(jī)制:
調(diào)用次數(shù)大于15或者設(shè)置noInflation=true,那么就可以看到GeneratedConstructorAccessorXXX和GeneratedMethodAccessorXXX類被JVM加載。
可以通過JVM參數(shù)-XX:+TraceClassLoading 和-Dsun.reflect.noInflation=true來查看JVM加載了這兩種類型的類。(ps: 只有接口實(shí)例調(diào)用方法才會有GeneratedMethodAccessorXXX)
[Loaded <font color="red">sun.reflect.GeneratedConstructorAccessor1 from JVM_DefineClass]</font>
[Loaded sun.reflect.BootstrapConstructorAccessorImpl from F:\softwares\JDK\jre1.8\lib\rt.jar]
[Loaded sun.misc.URLClassPath from F:\softwares\JDK\jre1.8\lib\rt.jar]
[Loaded sun.net.www.protocol.jar.Handler from F:\softwares\JDK\jre1.8\lib\rt.jar]
[Loaded sun.reflect.GeneratedConstructorAccessor2 from JVM_DefineClass]
.....
[Loaded <font color="red">sun.reflect.GeneratedMethodAccessor1 from JVM_DefineClass]</font>
[Loaded sun.reflect.GeneratedConstructorAccessor4 from JVM_DefineClass]
若是按照常規(guī)noInflation=false的時(shí)候,就應(yīng)該調(diào)用JNI來通過本地Native實(shí)現(xiàn)類來生成和加載類:(且有緩存,通常只是加載一遍那個(gè)類)
[Loaded sun.reflect.ReflectionFactory$1 from F:\softwares\JDK\jre1.8\lib\rt.jar]
[Loaded sun.reflect.NativeConstructorAccessorImpl from F:\softwares\JDK\jre1.8\lib\rt.jar]
[Loaded sun.reflect.DelegatingConstructorAccessorImpl from F:\softwares\JDK\jre1.8\lib\rt.jar]
......
[Loaded sun.reflect.NativeMethodAccessorImpl from F:\softwares\JDK\jre1.8\lib\rt.jar]
[Loaded sun.reflect.DelegatingMethodAccessorImpl from F:\softwares\JDK\jre1.8\lib\rt.jar]
完結(jié)。

今天下雨了,無所思,無所感。
不患寡而患不安,就如被雨水不斷擊打的地面,心里無名的....