本源碼主要是基於2.7.7-release版本. Dubbo中代理的擴展點是ProxyFactory接口,默認SPI擴展點是 javassist, 是經過Proxy#getProxy方案,傳入接口,而後調用newInstance 建立動態代理,這裏Proxy是Dubbo實現的代理抽象類,並非jdk的原生的Proxy,可是這列InvokerInvocationHandler仍是實現JDK原生的InvocationHandler接口. 經過ClassUtil#getClassLoader獲取classloader,調用蟲重載方法,傳入classloader和代理的接口. 加下來是具體建立代理的邏輯,1 首先校驗接口的數量不能超過 65535,而後把全部接口名稱拼接做爲緩存的key. 這是Proxy的緩存的數據結構, 就是Map嵌套的WeakHashMap 數據結構. 這裏對cache操做加了一把同步鎖,首先是會根據classloader取獲取HashMap的緩存,而後根據key 獲取代理代理,若是緩存已存在, 則直接返回緩存,沒有則判斷value是不是PENDING_GENERATION_MARKER(便是Object阻塞標誌),若是是 則一直調用wait進行等待待代理類的建立完成, 而後建立代理類計數器加1,而後實例化ClassGenerator類, 這是Dubbo首先的字節碼操做,而後檢查非public接口是否來自 不一樣的包, 而後遍歷解析接口的方法,加入到CodeGenerator實例, 然歐建立默認生成ProxyInstance類名規則是 包名 + ".proxy" + 自增id, 生成Proxy的實例,是Proxy.class.getName() + id, 而後調用ClassGenerator生成的toClass底層是經過 javasist生成字節碼,而後經過classloader記載到內存 java
Dubbo框架中沒有提供將生成的字節碼輸出到文件的配置,因此我加了如下代碼在生成字節碼後,寫入到文件:緩存
String proxyName = "$Proxy" + id +".class";
Path path = Paths.get(proxy
Files.write(path, mCtc.toBytecode(), new OpenOption[0]);
複製代碼
而後,下面是生成的字節碼反編譯的文件.markdown
第一個是代理的實例的類.數據結構
public class Proxy0 extends Proxy implements DC {
public Object newInstance(InvocationHandler var1) {
return new proxy0(var1);
}
public Proxy0() {
}
}
複製代碼
第二個是代理類框架
public class proxy0 implements DC, Destroyable, EchoService, DemoService {
public static Method[] methods;
private InvocationHandler handler;
public Object invoke(String var1, String var2) throws Exception {
Object[] var3 = new Object[]{var1, var2};
Object var4 = this.handler.invoke(this, methods[0], var3);
return (Object)var4;
}
public String get(CustomArgument var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[1], var2);
return (String)var3;
}
public long timestamp() {
Object[] var1 = new Object[0];
Object var2 = this.handler.invoke(this, methods[2], var1);
return var2 == null ? (long)0 : (Long)var2;
}
public int getSize(Object[] var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[3], var2);
return var3 == null ? 0 : (Integer)var3;
}
public int getSize(String[] var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[4], var2);
return var3 == null ? 0 : (Integer)var3;
}
public void $invoke(String var1, String var2) {
Object[] var3 = new Object[]{var1, var2};
this.handler.invoke(this, methods[5], var3);
}
public byte getbyte(byte var1) {
Object[] var2 = new Object[]{new Byte(var1)};
Object var3 = this.handler.invoke(this, methods[6], var2);
return var3 == null ? (byte)0 : (Byte)var3;
}
public void sayHello(String var1) {
Object[] var2 = new Object[]{var1};
this.handler.invoke(this, methods[7], var2);
}
public String getThreadName() {
Object[] var1 = new Object[0];
Object var2 = this.handler.invoke(this, methods[8], var1);
return (String)var2;
}
public int stringLength(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[9], var2);
return var3 == null ? 0 : (Integer)var3;
}
public Type enumlength(Type[] var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[10], var2);
return (Type)var3;
}
public Person getPerson(Person var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[11], var2);
return (Person)var3;
}
public String testReturnType(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[12], var2);
return (String)var3;
}
public List testReturnType1(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[13], var2);
return (List)var3;
}
public CompletableFuture testReturnType2(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[14], var2);
return (CompletableFuture)var3;
}
public CompletableFuture testReturnType3(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[15], var2);
return (CompletableFuture)var3;
}
public CompletableFuture testReturnType4(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[16], var2);
return (CompletableFuture)var3;
}
public CompletableFuture testReturnType5(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[17], var2);
return (CompletableFuture)var3;
}
public String echo(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[18], var2);
return (String)var3;
}
public Object $echo(Object var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[19], var2);
return (Object)var3;
}
public void $destroy() {
Object[] var1 = new Object[0];
this.handler.invoke(this, methods[20], var1);
}
public proxy0() {
}
public proxy0(InvocationHandler var1) {
this.handler = var1;
}
}
複製代碼
總結: 今天主要分析了Dubbo中基於Javasist的動態代理的實現過程,針對Javasist具體詳細操做須要讀者對於java的字節碼足夠了解, 我以前分析過Java字節碼文件的分析的文章,僅供參考.this