本源码主要是基于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记载到内存
Dubbo框架中没有提供将生成的字节码输出到文件的配置,所以我加了以下代码在生成字节码后,写入到文件:
String proxyName = "$Proxy" + id +".class";
Path path = Paths.get(proxy
Files.write(path, mCtc.toBytecode(), new OpenOption[0]);
然后,下面是生成的字节码反编译的文件.
第一个是代理的实例的类.
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字节码文件的分析的文章,仅供参考.