官方文档目前的内容时基于2.6.x版本的,我下载的源码是2.7.2的。大体内容以官方文档为主,这里记一些官方文档不全的/自己看文档时迷惑过的内容。
服务导出
Dubbo以ServiceConfig
, ReferenceConfig
为中心,对应的Spring入口就是ServiceBean
、ReferenceBean
。服务导出就是从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协议和Transporter
dubbo支持的RPC协议除了我们平常用的比较多的dubbo、http以外,还支持很多协议,下面是dubbo 2.7.2所支持的dubbo协议。
各个协议使用的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。