Dubbo服务提供者发布及注册过程源码分析

Dubbo服务端在启动服务时会经历怎样的调用过程?在收到消费者发送的请求后会经历怎样的调用过程?这篇文章主要针对以上两个调用过程并结合Dubbo源码进行分析。

我们采用的是Consumer-Provider的Demo提供的示例,并按照《Dubbo消费者调用过程源码分析》中的分析思路,下面将对两种过程进行进一步分析,先来看一张服务发布过程的时序图(图片太大建议在新的窗口打开查看),对服务发布与注册有个大致的了解:

基于Spring构建Dubbo源码分析

从Dubbo 2.7.0的项目依赖来看,依赖的Spring Framework版本是4.3.16.RELEASE

1
2
3
4
5
6
7
8
9
10
<properties>
<spring_version>4.3.16.RELEASE</spring_version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring_version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

Dubbo是基于Spring构建和运行的,兼容Spring配置,Dubbo利用了SpringFramework的Extensible XML authoring 特性,扩展了Spring标签,关于如何利用Spring扩展标签,可以参考官方文档 《Extensible XML authoring》

  • 编写xml,描述需要扩展的标签的配置属性,dubbo实现放在jar包META-INF/dubbo.xsd文件里 同时通过编写META-INF/spring.handlers文件,提供给spring,内容如下:

    1
    2
    http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
    http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
  • 编写一个NamespaceHandler接口实现类,dubbo中的实现类是DubboNamespaceHandler,同时通过编写META-INF/spring.schemas文件提供给Spring,内容如下:

    1
    2
    http\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
    http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd
  • 编写一个或多个BeanDefinitionParser实现类,用来解析扩展的元素,Dubbo实现类是DubboBeanDefinitionParaser

  • 把以上解析组件注册给Spring

Dubbo SPI机制源码分析

Dubbo是微内核架构,还是开闭原则的应用,把核心流程架构固定,但是流程的各个节点对重新改进是开放的。具体的实现机制就是SPI(Service Provider Interface)机制,Dubbo基于Java SPI机制(不了解Java SPI机制的可以参考这篇文章《深入理解Java SPI机制》),在其基础上做了改进和扩展。

根据SPI规范,接口由框架定义,具体实现可以由不同的厂商提供,在Dubbo jar包可以发现在/META-INF/dubbo/internal目录下有许多接口命名的文件,文件里面的内容就是文件名代表的接口的各种实现类,这就是Dubbo SPI机制的配置基础,以org.apache.dubbo.rpc.Protocol文件为例,内容如下(dubbo-2.7.0-SNAPSHOT 版本):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol
http=org.apache.dubbo.rpc.protocol.http.HttpProtocol

org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=org.apache.dubbo.rpc.protocol.redis.RedisProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
registry=org.apache.dubbo.registry.integration.RegistryProtocol
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper

Dubbo消费者调用过程源码分析

在分析Dubbo RPC服务调用过程之前,我们先写一个基于Dubbo实现的Consumer-Provider的Demo,通过这个Demo来分析具体的RPC调用栈。

先定义一个接口:

1
2
3
4
5
6
7
/**
* @author Junlan Shuai[shuaijunlan@gmail.com].
* @date Created on 11:02 AM 2018/07/19.
*/
public interface ITestService {
String sayHello(String msg);
}

我们基于zookeeper注册中心,服务端配置如下:

1
2
3
4
5
6
7
8
<dubbo:application name="dubbo-server" owner="Junlan" />
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!--protocal configuration-->
<dubbo:protocol name="dubbo" port="20881"/>
<dubbo:provider server="netty"/>
<!--service configuration-->
<dubbo:service interface="cn.shuaijunlan.dubbo.learning.service.ITestService" ref="testService" protocol="dubbo" loadbalance="roundrobin"/>
<bean class="cn.shuaijunlan.dubbo.learning.service.impl.TestServiceImpl" name="testService" />

客户端配置如下:

1
2
3
4
<dubbo:application name="dubbo-client" owner="Junlan"/>
<dubbo:consumer client="netty"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="cn.shuaijunlan.dubbo.learning.service.ITestService" id="testService" check="false"/>

Dubbo基于Javassist实现动态代理分析

1
2
3
4
5
org.apache.dubbo.common.bytecode.Proxy	//生成代理类
org.apache.dubbo.common.bytecode.ClassGenerator //基于javassist封装

org.apache.dubbo.common.utils.ClassHelper; //工具类
org.apache.dubbo.common.utils.ReflectUtils; //工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// create ProxyInstance class.
//生成代理类的实例
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));

// create Proxy class.
//生成代理类,通过调用newInstance()方法获取实例
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class<?> pc = ccm.toClass();
proxy = (Proxy) pc.newInstance();
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×