前言不得不说一下自己对dubbo源码的感想:著名的框架,其内在架构设计都非常漂亮并具有工程性
从调试的角度去看待源码
- 代理工厂
无论是服务消费者还是服务提供者,都得对调用服务的interface进行proxy,代理工厂具有两个,分别为javassist和jdk proxy
1 | org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory |
其中它们都具有getProxy、getInvoker方法实现
getProxy:主要用于服务消费者对interface进行代理,生成实例提供程序调用。而InvokerInvocationHandler是实际调用对象,其对上层程序代码隐藏了远程调用的细节1
2
3public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
getInvoker:主要用于服务提供者对实际被调用实例进行代理包装,以实现实际对象方法被调用后,进行结果、异常的CompletableFuture的封装
1 | @Override |
InvokerInvocationHandler:
1 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
AbstractProxyInvoker:
1 | public Result invoke(Invocation invocation) throws RpcException { |
- 服务提供者启动时,先创建相应选择的协议对象(Protocol),然后通过代理工厂创建Invoker对象,接着使用协议对象对Invoker进行服务注册至注册中心。
- 服务消费者启动时,先创建相应选择的协议对象(Protocol),然后通过协议对象引用到服务提供者,得到Invoker对象,接着通过代理工厂创建proxy对象。
- 服务消费者spring配置了dubbo:reference,在spring容器创建bean时,先创建FactoryBean(ReferenceBean extends ReferenceConfig),在getObject时调用ReferenceConfig的get方法,在get方法中init初始化,接着调用createProxy并传入相应参数创建代理对象,紧接着使用SPI方式得到代理工厂适配器、注册协议对象,默认获得javassist代理工厂创建代理,然后使用协议对象(ProtocolFilterWrapper-ProtocolListenerWrapper-QosProtocolWrapper-RegisterProtocol)调用doRefer,并且根据protocol得到spring配置的dubbo:registry使用的是zookeeper协议,通过SPI得到ZookeeperRegister的注册中心去注册订阅,接着生成RegisterDirectory封装服务相关数据,然后通过SPI加载FailoverCluster,生成Invoker对象,得到服务引用(MockClusterInvoker包装着FailoverCluster),最后通过代理工厂创建代理实例,个人认为Cluster是对服务提供者集群的高可用设计,在某个服务不可用时可以故障转移。
- 服务消费者调用代理对象时,先判断是否一些Object方法,若是Object方法,则直接本地调用,否则创建RpcInvocation封装调用目标方法、接口、参数等信息,然后调用Invoker的invoke方法,一般情况下,invoker对象是一系列invoker的包装(默认MockClusterInvoker-FailoverClusterInvoker-InvokerWrapper-ListenerInvokerWrapper-ProtocolFilterWrapper-DubboInvoker)。
- 服务集群,当使用服务集群时,在invoker执行远程调用时,会进行负载均衡选择集群中的某个invoker进行远程调用
- FailoverClusterInvoker,故障转移集群invoker中会根据配置中的失败重试次数进行失败重试
从简单阅读的角度去看待源码
dubbo-container容器
- dubbo-container:dubbo容器实现,它的容器并不是沙盒形式的容器。从dubbo-container-api可以看出,其具有main启动方法,根据系统变量dubbo.container或java启动参数读取配置指定需要启动的容器(英文逗号分隔),并使用系统变量dubbo.shutdown.hook去配置是否对启动的容器进行jvm shutdown的hook,以实现shutdown时对容器进行关停
1 | public class Main { |
- dubbo-container-spring:spring容器实现包,系统变量dubbo.spring.config读取spring配置文件位置或使用默认位置classpath:META-INF/spring/.xml读取,主要是读取spring文件并启动spring容器
1 | public class SpringContainer implements Container { |
- dubbo-container-log4j:log4j容器,主要是使用dubbo容器时,可以独立加入使用log4j打印日志,系统变量dubbo.log4j.file配置日志输出文件,系统变量dubbo.log4j.level配置日志输出level,系统变量dubbo.log4j.subdirectory设置日志输出目录其会修改当前所以logger appender的输出目录为此目录
1 | public class Log4jContainer implements Container { |
- dubbo-container-logback:logback容器,与log4j容器差不多,系统变量dubbo.logback.file、dubbo.logback.level都分别是对输出文件、输出level的配置,而系统变量dubbo.logback.maxhistory配置log文件最大保存历史(文件以”.%d{yyyy-MM-dd}”结尾)
1 | public class LogbackContainer implements Container { |
dubbo-registry注册中心
- registry注册中心:在dubbo中主要负责服务暴露、引用,服务暴露主要是服务提供者启动时,告诉注册中心其要对外暴露一个服务,服务消费者可通过注册中心获取到所有服务提供者的信息(并实时监听数据变动),然后通过得到的信息完成远程调用。
- RegistryProtocol:在服务提供端或服务消费端启动时,都会通过其进行暴露或引用服务。若使用了registry=zookeeper&protocol=dubbo,则在启动时,提供者会先使用ZookeeperRegistry把当前服务的信息注册至zookeeper,然后使用DubboProtocol对其服务进行暴露处理(若使用remoting实现为netty,则会建立端口监听)得到ExchangeServer,而消费者则先使用ZookeeperRegistry通过zookeeper订阅并获取提供者服务信息,然后使用DubboProtocol对其服务进行引用得到一个或多个ExchangeClient,接着用cluster进行包装,对外层隐藏细节,从而实现集群、故障转移等特性
dubbo-remoting远程通讯包
- remoting远程通讯包:其封装了buffer、exchange、telnet、transport层,对上层隐藏细节,默认使用netty实现远程通讯
- Exchanger:交换层,隐藏下一层传输层的细节,对下层包装Request、Response,下层仅需关心是请求还是响应。bind方法为服务提供者在Protocol中对服务的bind,得到ExchangeServer。connect方法为服务消费者在Protocol中对服务的connect,得到ExchangeClient。而无论是服务的提供者还是消费者,在bind、connect时,都需要提供ExchangeHandler,其被用于解码请求,对于提供者,其为请求接收处理,其在Protocol层,不关心remoting实现细节,只管接收到Request对象,然后invoke服务实现并返回Result。
- ExchangeServer:服务提供者对服务暴露时,使用Protocol对象进行export,export中对其进行Exchangers.bind得到ExchangeServer,其重点为第二个参数ExchangeHandler,其被多个handler进行包装,进行了多层的处理,其为最外层,进行实际实例方法的调用invoke,然后返回Result
- ExchangeClient:服务消费者对服务引用时,使用Protocol对象进行refer,refer中中对其进行Exchangers.connect得到ExchangeClient,然后把其封装在Invoker中,接着Invoker被proxy,当消费者执行Proxy对象方法时,其会通过InvokeInvocationHandler对Invoker进行invoke,然后Invoker调用ExchangeClient进行request,其重点为第二个参数ExchangeHandler,其被多个handler进行包装,进行了多层的处理,其为最外层,对响应进行处理DefaultFuture.received
- DefaultFuture:在消费者Invoker对ExchangeClient进行request时,都会创建DefaultFuture并放置在其内部static集合FUTURES中以表示正在进行的请求,然后立即返回,当有响应Response返回时调用received,会将其在FUTURES集合中删除,然后把相应结果放到CompletableFuture
- Transporters:交换层Exchangers的bind、connect最终都交由传输层Transporters处理
- HeaderExchanger:无论是bind还是connect都传入了多层handler,DecodeHandler-HeaderExchangeHandler-ExchangeHandler,对于服务双方来讲,都是Handler都是对接收消息的处理。DecodeHandler对接收消息进行判断,若是请求(即提供方),则对Data进行decode,若是响应(即消费者),则对Result进行decode。HeaderExchangeHandler对请求进行实际方法调用,此时区分request.isEvent、request.isTwoWay等,最终调用最外层的ExchangeHandler。
- HeaderExchangeClient:默认ExchangeClient的实现,其由HeaderExchanger创建,构造方法中创建HeaderExchangeChannel,而其Client由Transporters(SPI可选,NettyTransporter)创建,当Invoker进行invoke时,通过其进行request并传入RpcInvocation,然后由HeaderExchangeChannel对其包装成Request对象,接着通过client进行send
- HeaderExchangeServer:默认ExchangeServer的实现,请求经过DecodeHandler-HeaderExchangeHandler-ExchangeHandler多层处理后调用实际实例方法,然后调用其bind时由Transporters(SPI可选,NettyTransporter)创建的server的send方法进行发送响应结果。
dubbo-rpc
- rpc上进行功能扩展的module
- filter、interceptors、listener:功能扩展