Netty中Future与Promise的实现分析

从Java 1.5开始,JDK就提供了Callable和Future,通过它们可以在任务异步执行完毕之后获取任务的执行结果。

Netty扩展了JDK中的Future机制,下面我们来看一张Netty中Future和Promise类关系图:

基于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"/>

深入理解Java SPI机制

SPI的全名为Service Provider Interface,在java.util.ServiceLoader的文档:https://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html中有比较详细的介绍。究其思想,其实和Callback差不多。Callback的思想是我们在调用API的时候,我们可以写入一段逻辑代码传到API里面,API内部在合适的时候会调用它,从而实现某种程度上的“定制”。

典型的是Collections.sort(List<T> list,Comparator<? super T> c)这个方法,它的第二个参数是一个实现Comparator接口的实例。我们可以根据自己的排序规则写一个类,实现此接口,传入此方法,那么这个方法就会根据我们的规则对list进行排序。

Java SPI的具体约定如下

当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。

JDK提供服务实现查找的一个工具类:java.util.ServiceLoader

Your browser is out-of-date!

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

×