Dubbo源码笔记(一)

Posted by RussXia on June 4, 2019

官方文档目前的内容时基于2.6.x版本的,我下载的源码是2.7.2的。大体内容以官方文档为主,这里记一些官方文档不全的/自己看文档时迷惑过的内容。

服务导出

Dubbo以ServiceConfig, ReferenceConfig 为中心,对应的Spring入口就是ServiceBeanReferenceBean。服务导出就是从ServiceBean开始的。

ServiceBean

ServiceBean实现了ApplicationListener接口,在 Spring中,每当一个ApplicationEvent发布到 ApplicationContext上时,实现了ApplicationListener的接口就会得到通知。调用对应的ApplicationListener#onApplicationEvent方法。

在ServiceBean的onApplicationEvent方法中,判断是否需要导出,如果需要,执行导出逻辑。

Javassist和JdkProxy 动态代理

dubbo中提供了Javassist和JDK两种动态代理方式,默认使用的是Javassist。如果需要,可以更改一下配置变更动态代理方式:

<!-- provider修改为jdk动态代理 -->
<dubbo:provider proxy="jdk" />
<!-- consumer修改为jdk动态代理 -->
<dubbo:consumer proxy="jdk" />

或者直接在org.apache.dubbo.config.ApplicationConfig中指定:

 <dubbo:application name="demo-provider" compiler="jdk"/>

关于动态代理技术,Java中常见的相关技术有:

  • JDK 动态代理
  • cglib 动态代理(依赖ASM字节码技术)
  • javassist 动态代理

其中,cglib底层依赖的是ASM,ASM的字节码技术和javassist的有很大的不一样,ASM操纵的级别是底层JVM的汇编指令级别,需要对class组织结构和JVM汇编指令有一定的了解。

//ASM框架demo
ClassWriter classWriter = new ClassWriter(0);  
// 通过visit方法确定类的头部信息  
classWriter.visit(Opcodes.V1_7,// java版本  
        Opcodes.ACC_PUBLIC,// 类修饰符  
        "Programmer", // 类的全限定名  
        null, "java/lang/Object", null);  
    
//创建构造函数  
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);  
mv.visitCode();  
mv.visitVarInsn(Opcodes.ALOAD, 0);  
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>","()V");  
...
...

而相对的,javassist就简单易于理解很多,javassist直接使用java编码的形式,不需要asm那么硬核。

 ClassPool pool = ClassPool.getDefault();  
//创建Programmer类       
CtClass cc= pool.makeClass("com.samples.Programmer");  
//定义code方法  
CtMethod method = CtNewMethod.make("public void code(){}", cc);  
//插入方法代码  
method.insertBefore("System.out.println(\"I'm a Programmer,Just Coding.....\");");  
cc.addMethod(method);  

其实cglib的动态代理(底层使用的ASM)速度也蛮快的(相较于jdk动态代理),而且使用起来也比asm和javassist方便很多,不过性能上比不过asm和javassist。

dubbo的作者基于性能的考虑,最后选择了javassist作为默认的动态代理实现。dubbo-梁飞-动态代理方案性能对比

dubbo现在已经支持SPI扩展,可以自定义实现org.apache.dubbo.rpc.ProxyFactory接口,扩展自己的代理方案也是ok的。

参考资料-深入理解RPC之动态代理篇

RPC协议和Transporter

dubbo支持的RPC协议除了我们平常用的比较多的dubbo、http以外,还支持很多协议,下面是dubbo 2.7.2所支持的dubbo协议。 dubbo支持的rpc协议

各个协议使用的Transporter各不相同,下面主要还是以dubbo protocol为主,看看dubbo暴露服务的过程。

//org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer
 ExchangeServer server;
try {
    // 创建 ExchangeServer
    server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
    throw new RpcException("Fail to start server...");
}

exchanger内部调用Transporter,Transporter的默认实现是netty对应的netty4版本,dubbo还支持netty3、mina、grizzly。