前言
上一節(jié)講了say方法最終會(huì)轉(zhuǎn)發(fā),在demo中
cglib.CglibProxy#intercept這個(gè)里面用了
Object result = methodProxy.invokeSuper(o, objects);
這個(gè)invokeSuper是什么孵淘?如何實(shí)現(xiàn)代理類(lèi)函數(shù)的調(diào)用 轉(zhuǎn)發(fā)到 父類(lèi)對(duì)應(yīng)函數(shù)的調(diào)用.
這里就涉及methodProxy以及FastClass機(jī)制了。
這兩者也是緊密聯(lián)系的。
源碼分析
方法代理的創(chuàng)建 CGLIB$methodName$index$Proxy
先直接講結(jié)論
*** 方法代理的作用就是指明class1.method1方法對(duì)應(yīng)的代理方法是class2.method2 ***
再看代碼
先看cglib.CglibProxy#intercept在前面代理類(lèi)class反編譯文件中傳遞的參數(shù)
Object object = methodInterceptor.intercept((Object)this, CGLIB$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy);
//CGLIB$say$0$Proxy是什么
CGLIB$say$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"say", (String)"CGLIB$say$0");
//其中
Class class_2 = Class.forName("java.lang.Object");
Class class_ = Class.forName("cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$4e65f4b");
上面代碼中与殃,MethodProxy#create
就是根據(jù)參數(shù)進(jìn)行"簽名"
A representation of a method signature, containing the method name,
return type, and parameter types.
簽名包含方法名稱(chēng),返回類(lèi)型碍现,以及參數(shù)類(lèi)型,看源碼如下
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
*** 這一段的意義就是說(shuō),委托類(lèi)c1的方法name1,對(duì)應(yīng)的代理方法是實(shí)現(xiàn)類(lèi)c2的方法name2***
方法代理的調(diào)用
再看net.sf.cglib.proxy.MethodProxy#invokeSuper干了啥
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
//init函數(shù)干了什么
private void init()
{
/*
單例模式實(shí)現(xiàn)
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
/*
生成fastClass f1,f2,結(jié)合class文件分析
*/
// System.out.println("net.sf.cglib.proxy.MethodProxy.helper " + ci.c1.getName() + " " + ci.c2.getName() + " " + this.sig1 + " " + this.sig2);
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
/*
獲取當(dāng)前方法在f1,f2中的簽名幅疼,得到一個(gè)index(方法與簽名,index是一一對(duì)應(yīng)的關(guān)系)
可以根據(jù)index映射對(duì)應(yīng)類(lèi)的對(duì)應(yīng)方法
*/
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
//helper函數(shù)干了什么
private static FastClass helper(CreateInfo ci, Class type) {
//根據(jù)ci得到該方法的委托類(lèi)昼接,實(shí)現(xiàn)類(lèi)爽篷,分別生成這兩個(gè)類(lèi)的fastClass
FastClass.Generator g = new FastClass.Generator();
g.setType(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
fastClass創(chuàng)建于調(diào)用
可以直接參考 http://www.cnblogs.com/cruze/p/3865180.html
這里說(shuō)的比較簡(jiǎn)單易懂
主要思想就是在為了避免方法調(diào)用時(shí),過(guò)度使用反射造成調(diào)用慢的問(wèn)題
給每一個(gè)方法一個(gè)簽名慢睡,遇到這個(gè)簽名時(shí)逐工,直接顯示調(diào)用實(shí)現(xiàn)類(lèi)的實(shí)現(xiàn)方法,
可以參考下面的fastClass文件
fastClass的創(chuàng)建
fastClass的創(chuàng)建時(shí)機(jī)
從demo中看膨疏,fastClass是根據(jù)這樣的順序創(chuàng)建的
net.sf.cglib.proxy.MethodProxy#invokeSuper
net.sf.cglib.proxy.MethodProxy#init
net.sf.cglib.proxy.MethodProxy#helper
net.sf.cglib.reflect.FastClass.Generator#create
*** 這里有一種lazy init的思想 ***
也就是說(shuō),一開(kāi)始并沒(méi)有fastClass钻弄,只有MethodProxy
但是當(dāng) 方法代理 真正被請(qǐng)求的時(shí)候
class1的method1方法需要映射到class2的method2方法時(shí),
為了避免過(guò)度使用反射,才生成了fastClass方便的完成調(diào)用
為了方便理解佃却,
fastClass的創(chuàng)建了幾次
即生成了幾個(gè)fastClass類(lèi)的class文件
*** 兩個(gè),f1和f2(理解成是fast(c1)和fast(c2)) ***
net.sf.cglib.proxy.MethodProxy#init里面調(diào)用了兩次net.sf.cglib.proxy.MethodProxy#helper
這兩個(gè)文件的區(qū)別是什么
對(duì)象 | 意義窘俺,實(shí)例 |
---|---|
c1 | cglib.CglibLearn$serviceImpl |
f1 | c1的fastClass,更方便調(diào)用c1的函數(shù) cglib.CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381 |
c2 | cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$b2e6ff51 即c1的enhance class |
f2 | c2的fastClass,更加方便調(diào)用c2的函數(shù), cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$b2e6ff51$$FastClassByCGLIB$$8a094902 |
f1,f2都是對(duì)原有的c1,c2進(jìn)行了method->signature->index的映射
fastClass類(lèi)的內(nèi)容是如何generate出來(lái)的
net.sf.cglib.reflect.FastClass.Generator#generateClass
這里就不細(xì)講了饲帅,和上一節(jié)Enhancer#generateClass干的事情一樣,難度更小瘤泪,底層還是利用asm生成灶泵。
fastClass類(lèi)的內(nèi)容是什么
以f1為例 (f2后面篩選一部分出來(lái)),即
cglib.CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381為例子,class反編譯的代碼如下
package cglib;
import cglib.CglibLearn.serviceImpl;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
/* compiled from: <generated> */
public class CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381 extends FastClass {
public CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381(Class cls) {
super(cls);
}
public int getIndex(String str, Class[] clsArr) {
switch (str.hashCode()) {
case -1776922004:
if (str.equals("toString")) {
switch (clsArr.length) {
case 0:
return 5;
default:
break;
}
}
break;
case -1295482945:
if (str.equals("equals")) {
switch (clsArr.length) {
case 1:
if (clsArr[0].getName().equals("java.lang.Object")) {
return 4;
}
break;
default:
break;
}
}
break;
case -1039689911:
if (str.equals("notify")) {
switch (clsArr.length) {
case 0:
return 8;
default:
break;
}
}
break;
case 113643:
if (str.equals("say")) {
switch (clsArr.length) {
case 0:
return 0;
default:
break;
}
}
break;
case 3641717:
if (str.equals("wait")) {
switch (clsArr.length) {
case 0:
return 1;
case 1:
if (clsArr[0].getName().equals("long")) {
return 3;
}
break;
case 2:
if (clsArr[0].getName().equals("long") && clsArr[1].getName().equals("int")) {
return 2;
}
default:
break;
}
}
break;
case 147696667:
if (str.equals("hashCode")) {
switch (clsArr.length) {
case 0:
return 6;
default:
break;
}
}
break;
case 1902066072:
if (str.equals("notifyAll")) {
switch (clsArr.length) {
case 0:
return 9;
default:
break;
}
}
break;
case 1950568386:
if (str.equals("getClass")) {
switch (clsArr.length) {
case 0:
return 7;
default:
break;
}
}
break;
}
return -1;
}
public int getIndex(Signature signature) {
String obj = signature.toString();
switch (obj.hashCode()) {
case -1725733088:
if (obj.equals("getClass()Ljava/lang/Class;")) {
return 7;
}
break;
case -1026001249:
if (obj.equals("wait(JI)V")) {
return 2;
}
break;
case -909388886:
if (obj.equals("say()V")) {
return 0;
}
break;
case 243996900:
if (obj.equals("wait(J)V")) {
return 3;
}
break;
case 946854621:
if (obj.equals("notifyAll()V")) {
return 9;
}
break;
case 1116248544:
if (obj.equals("wait()V")) {
return 1;
}
break;
case 1826985398:
if (obj.equals("equals(Ljava/lang/Object;)Z")) {
return 4;
}
break;
case 1902039948:
if (obj.equals("notify()V")) {
return 8;
}
break;
case 1913648695:
if (obj.equals("toString()Ljava/lang/String;")) {
return 5;
}
break;
case 1984935277:
if (obj.equals("hashCode()I")) {
return 6;
}
break;
}
return -1;
}
public int getIndex(Class[] clsArr) {
switch (clsArr.length) {
case 0:
return 0;
default:
return -1;
}
}
public int getMaxIndex() {
return 9;
}
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
serviceImpl cglib_CglibLearn_serviceImpl = (serviceImpl) obj;
switch (i) {
case 0:
try {
cglib_CglibLearn_serviceImpl.say();
return null;
} catch (Throwable th) {
invocationTargetException = new InvocationTargetException(th);
}
case 1:
cglib_CglibLearn_serviceImpl.wait();
return null;
case 2:
cglib_CglibLearn_serviceImpl.wait(((Number) objArr[0]).longValue(), ((Number) objArr[1]).intValue());
return null;
case 3:
cglib_CglibLearn_serviceImpl.wait(((Number) objArr[0]).longValue());
return null;
case 4:
return new Boolean(cglib_CglibLearn_serviceImpl.equals(objArr[0]));
case 5:
return cglib_CglibLearn_serviceImpl.toString();
case 6:
return new Integer(cglib_CglibLearn_serviceImpl.hashCode());
case 7:
return cglib_CglibLearn_serviceImpl.getClass();
case 8:
cglib_CglibLearn_serviceImpl.notify();
return null;
case 9:
cglib_CglibLearn_serviceImpl.notifyAll();
return null;
default:
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
invocationTargetException = new InvocationTargetException(th);
}
public Object newInstance(int i, Object[] objArr) throws InvocationTargetException {
switch (i) {
case 0:
try {
return new serviceImpl();
} catch (Throwable th) {
InvocationTargetException invocationTargetException = new InvocationTargetException(th);
}
default:
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
}
如何理解上面這段代碼,先看父類(lèi)fastClass的幾個(gè)函數(shù)定義
//根據(jù)方法簽名的hashCode,獲取一個(gè)method的標(biāo)識(shí)index
net.sf.cglib.reflect.FastClass#getIndex(net.sf.cglib.core.Signature)
//根據(jù)method的標(biāo)識(shí)index,調(diào)用實(shí)現(xiàn)類(lèi)的對(duì)應(yīng)方法
net.sf.cglib.reflect.FastClass#invoke(int, java.lang.Object, java.lang.Object[])
*** 為什么說(shuō)fastClass比反射快 ***
net.sf.cglib.reflect.FastClass#invoke(int, java.lang.Object, java.lang.Object[])函數(shù)中对途,直接創(chuàng)建了實(shí)現(xiàn)類(lèi)對(duì)象赦邻,通過(guò)標(biāo)識(shí)符index去switch case進(jìn)行對(duì)應(yīng)調(diào)用,就像上面的
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
serviceImpl cglib_CglibLearn_serviceImpl = (serviceImpl) obj;
switch (i) {
case 0:
try {
cglib_CglibLearn_serviceImpl.say();
return null;
} catch (Throwable th) {
invocationTargetException = new InvocationTargetException(th);
}
//省略
結(jié)果分析
上面invokeSuper返回
fci.f2.invoke(fci.i2, obj, args)
是干了什么
表示用方法代理(否則是f1,這里是f2),將lazy init里面記錄好的方法簽名對(duì)應(yīng)的標(biāo)志i2傳遞過(guò)去实檀,讓f2進(jìn)行對(duì)應(yīng)的處理
上面fastclass是f1的惶洲,這里只貼出來(lái)f2對(duì)應(yīng)部分,f2比較長(zhǎng)
類(lèi)名
cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$b2e6ff51$$FastClassByCGLIB$$8a094902
public int getIndex(Signature signature) {
String obj = signature.toString();
switch (obj.hashCode()) {
case 1540695073:
if (obj.equals("CGLIB$say$0()V")) {
return 17;
}
break;
}
}
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
b2e6ff51 cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51 = (b2e6ff51) obj;
switch (i) {
case 17:
cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51.CGLIB$say$0();
return null;
default:
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
//cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51.CGLIB$say$0()函數(shù)
final void CGLIB$say$0() {
super.say();//即CglibLearn.serviceImpl.say()方法
}
這里就完成了c1.say到c2.CGLIB$say$0()的轉(zhuǎn)發(fā)
可能會(huì)有疑問(wèn)膳犹,為什么不是c1.say到c2.say的轉(zhuǎn)發(fā)
這是因?yàn)樵赾2里面定義了(上一節(jié)也有這段代碼,本節(jié)最上也有)
CGLIB$say$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"say", (String)"CGLIB$say$0");
//其中
Class class_2 = Class.forName("java.lang.Object");
Class class_ = Class.forName("cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$4e65f4b");
將Object的say方法 代理 給了 serviceImpl$$EnhancerByCGLIB$$4e65f4b的 CGLIB$say$0方法
即表明恬吕,c1的say方法轉(zhuǎn)發(fā)到了c2的CGLIB$say$0方法
思考
1.fastclass比反射快的原因
通過(guò)方法前面或者標(biāo)識(shí)符index,利用switch case直接利用對(duì)象去調(diào)用函數(shù)
而反射是java.lang.reflect.Method#invoke,稍微復(fù)雜點(diǎn)须床,這個(gè)沒(méi)研究過(guò)具體實(shí)現(xiàn)
2.MethodProxy#invoke和MethodProxy#invokeSuper什么區(qū)別铐料,即[c1,f1]與[c2,f2]的區(qū)別
[c1,f1]對(duì)應(yīng)的是 父類(lèi)的class和fastclass
[c2,f2]對(duì)應(yīng)的是 父類(lèi)的enhanceClass和 enhanceFastClass
3.MethodProxy#init創(chuàng)建fastclass時(shí),每個(gè)method在第一次調(diào)用時(shí),都會(huì)進(jìn)行
net.sf.cglib.proxy.MethodProxy#init
net.sf.cglib.proxy.MethodProxy#helper
net.sf.cglib.reflect.FastClass.Generator#create
那么為什么對(duì)應(yīng)的fastclass文件只生成了一次(不是一個(gè)method調(diào)用一次就生成一次)
并且一次就有整個(gè)類(lèi)的信息豺旬,而不是只有這個(gè)method相關(guān)信息呢
第一點(diǎn):同一個(gè)類(lèi)的fastClass只生成了一次钠惩,
是
net.sf.cglib.reflect.FastClass.Generator#create
net.sf.cglib.core.AbstractClassGenerator#create
里面用了緩存
第二點(diǎn):一次就有整個(gè)類(lèi)的信息,而不是只有這個(gè)method信息
net.sf.cglib.proxy.MethodProxy#create時(shí)就傳入和class c1,c2
后來(lái)創(chuàng)建fastClass時(shí)
net.sf.cglib.proxy.MethodProxy#helper
調(diào)用了g.setType(type);
在fastClass生成時(shí)
net.sf.cglib.reflect.FastClass.Generator#generateClass
用到了這個(gè)之前設(shè)置好的Class type族阅,也就直到類(lèi)信息了
invokeSuper的邏輯
4.把invokeSuper改成invoke會(huì)怎么樣
結(jié)論:死循環(huán)篓跛,堆棧溢出
原因分析:就相當(dāng)于MethodProxy方法代理中,并沒(méi)有代理
看c1.say方法耘分,上一節(jié)有列舉出來(lái)
final void say() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
methodInterceptor.intercept(this, CGLIB$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy);
} else {
say();
}
}
這里會(huì)走到methodInterceptor.intercept,會(huì)進(jìn)過(guò)aop
本來(lái)調(diào)用invokeSuper举塔,在這里如果改成了invoke,那么
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
會(huì)用f1(之前invokeSuper用的f2),f1的代碼參照上面列舉出來(lái)的對(duì)應(yīng)邏輯
//getIndex中say方法前面返回0作為index
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
serviceImpl cglib_CglibLearn_serviceImpl = (serviceImpl) obj;
switch (i) {
case 0:
try {
cglib_CglibLearn_serviceImpl.say();
return null;
} catch (Throwable th) {
invocationTargetException = new InvocationTargetException(th);
}
也就是說(shuō)serviceImpl.say()通過(guò)invoke(非invokeSuper)最終還是回到了serviceImpl.say(),變成了遞歸導(dǎo)致堆棧溢出求泰。
5.methodProxy和fastClass結(jié)合使用
methodProxy用于生成方法代理的關(guān)系綁定(classA.methodA被classB.methodB代理)
fastClass用于完成方法代理的快速調(diào)用央渣,通過(guò)簽名拿到標(biāo)識(shí)index,避免重復(fù)反射
吐槽
1.methodProxy負(fù)責(zé)了fastClass的生成渴频,但是methodProxy多次調(diào)用生成fastClass芽丹,還要讓fastClass最終只有一份class文件
也就是調(diào)用代理方法時(shí),再創(chuàng)建fastEnhance類(lèi)卜朗,再轉(zhuǎn)發(fā)過(guò)去
這種lazy的思想感覺(jué)超出了自己的職責(zé)
2.c1,c2,f1,f2的關(guān)系有點(diǎn)繞
3.文檔少
4.反編譯用http://www.javadecompilers.com/
方式選擇CFR (very good and well-supported decompiler for Java 8)
不要選Jadx, fast and with Android support
否則代碼會(huì)讓人誤解拔第,比如
//cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51.CGLIB$say$0()函數(shù)在不同反編譯方式下
//CFR (very good and well-supported decompiler for Java 8)方式
final void CGLIB$say$0() {
super.say();//即CglibLearn.serviceImpl.say()方法
}
//Jadx, fast and with Android support
final void CGLIB$say$0() {
say();//super沒(méi)了!!!讓我以為invokeSuper函數(shù)最終也會(huì)產(chǎn)生遞歸!!!
}