dubbo源码深度解读之rpc模块

dubbo源码深度解读之rpc模块

前言:rpc模块是远程调用模块,抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。这个模块的学习将使我们对服务的发布和调用更加清晰。

重点学习这几个类的作用和它们的实现类:ProxyFactory、Invoker、Protocol、Exporter

Invoker

这是一个可执行的对象,能够根据方法,参数得到执行结果,代码如下:

public interface Invoker<T> extends Node { Class<T> getInterface(); Result invoke(Invocation invocation) throws RpcException;}

里面的Invocation包含了要执行的方法和参数

public interface Invocation { String getMethodName(); Class<?>[] getParameterTypes(); Object[] getArguments(); Map<String, String> getAttachments(); String getAttachment(String key); String getAttachment(String key, String defaultValue); Invoker<?> getInvoker();}

看一下Invocation的实现类:RpcInvocation。简略代码如下:

public class RpcInvocation implements Invocation, Serializable { private static final long serialVersionUID = -4355285085441097045L; private String methodName; private Class<?>[] parameterTypes; private Object[] arguments; private Map<String, String> attachments; private transient Invoker<?> invoker;}

其实也只是提供了Invocation所需的参数而已。我们把目光又放回Invoker。

Invoker的执行过程分为三种类型

(1)本地执行类的Invoker

(2)远程通信执行类的Invoker

(3)多个(2)的Invoker聚合成的集群版的Invoker(需要设计到负载均衡)

dubbo源码深度解读之rpc模块

ProxyFactory

对于server端,主要负责将服务统一进行包装成一个Invoker,这些Invoker通过反射来执行具体的对象的方法。

@SPI("javassist")public interface ProxyFactory { @Adaptive({Constants.PROXY_KEY}) <T> T getProxy(Invoker<T> invoker) throws RpcException; @Adaptive({Constants.PROXY_KEY}) <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;}

实现类主要有JdkProxyFactory、JavassistProxyFactory。默认是JavassistProxyFactory

Protocol

我们发布服务的第一个过程是将服务封装成一个本地执行的invoker,执行服务这个就是执行这个invoker(调用这个invoker的invoke方法),通过反射执行。但是我们看到invoke方法的参数-invocation,这个参数是如何得来的?

服务端的Protocol需要根据指定的协议对外公布服务,当客户端根据协议调用这个服务时候,将用户传递的invocation参数交给invoker来执行,所以Protocol加入了远程通信协议这一块,根据用户的请求获取参数Invocation。

@Extension("dubbo")public interface Protocol { int getDefaultPort(); @Adaptive <T> Exporter<T> export(Invoker<T> invoker) throws RpcException; @Adaptive <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException; void destroy();}

服务发布的第二步是暴露invoker。

Exporter<?> exporter = protocol.export(invoker);

暴露过程即根据invoker的URL的配置信息来最终选择Protocol实现,默认是dubbo,扩展实现即DubboProtocol,然后再对DubboProtocol进行依赖注入,进行wrap包装。先来看看Protocol的实现情况:

可以看到在返回DubboProtocol之前,经过了ProtocolFilterWrapper(核心方法是buildInvokerChain,构建Chain)、ProtocolListenerWrapper、RegistryProtocol的包装。

包装时候的是装饰模式,类似AOP功能

dubbo源码深度解读之rpc模块

package com.alibaba.xxx;import com.alibaba.dubbo.rpc.Protocol;public class XxxProtocolWrapper implemenets Protocol { Protocol impl; public XxxProtocol(Protocol protocol) { impl = protocol; } // 接口方法做一个操作后,再调用extension的方法 public Exporter<T> export(final Invoker<T> invoker) { //... 一些操作 impl .export(invoker); // ... 一些操作 } // ...}

当服务发布时候会先经过RegistryProtocol,这个类的主要功能如下:

1,利用内部的Protocol即DubboProtocol,将服务进行导出,

2,根据注册中心的registryUrl获取注册服务Registry,然后将serviceUrl注册到注册中心上,供客户端订阅

接下来就需要看到DubboProtocol类了,注重看它的服务导出功能。

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl() // export service. String key = serviceKey(url) DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap) exporterMap.put(key, exporter) //export an stub service for dispaching event Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT) Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false) if (isStubSupportEvent && !isCallbackservice){ String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY) if (stubServiceMethods == null || stubServiceMethods.length() == 0 ){ if (logger.isWarnEnabled()){ logger.warn(new IllegalStateException("consumer [" +url.getParameter(Constants.INTERFACE_KEY) + "], has set stubproxy support event ,but no stub methods founded.")) } } else { stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods) } } openServer(url) return exporter }

创建一个DubboExporter,封装invoker。然后根据url的port、path(接口的名称)、版本号、分组号作为key,将DubboExporter存至Map

dubbo源码深度解读之rpc模块

private void openServer(URL url) { String key = url.getAddress(); boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true); if (isServer) { ExchangeServer server = serverMap.get(key); if (server == null) { serverMap.put(key, createServer(url)); } else { server.reset(url); } } }

首先根据Invoker的url获取ExchangeServer通信对象(负责与客户端的通信模块),以url中的host和port作为key存至Map

private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() { public Object reply(ExchangeChannel channel, Object message) throws RemotingException { if (message instanceof Invocation) { Invocation inv = (Invocation) message; Invoker<?> invoker = getInvoker(channel, inv); RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress()); return invoker.invoke(inv); } throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress()); }};

可以看到在获取到Invocation参数后,调用getInvoker(channel, inv)来获取本地Invoker。获取过程就是根据channel获取port,根据Invocation inv信息获取要调用的服务接口、版本号、分组号等,以此组装成key,从上述Map

public interface Exporter<T> { Invoker<T> getInvoker(); void unexport();}

包含了一个Invoker对象。一旦想撤销该服务,就会调用Invoker的destroy()方法,同时清理上述exporterMap中的数据。对于RegistryProtocol来说就需要向注册中心撤销该服务

DubboCodec

这个类是上一篇遗留的,当初涉及到编解码问题,接下来就来解读dubbo传输的底层协议组成以及它的编码解码过程。

1,传输协议

协议格式

2,header

dubbo源码深度解读之rpc模块

3,bodydata

是消息传递的真正内容,body的占用的字节大小由协议头后四位保存。

4,序列化Request和Response

@Override protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { RpcInvocation inv = (RpcInvocation) data out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION)) out.writeUTF(inv.getAttachment(Constants.PATH_KEY)) out.writeUTF(inv.getAttachment(Constants.VERSION_KEY)) out.writeUTF(inv.getMethodName()) out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes())) Object[] args = inv.getArguments() if (args != null) for (int i = 0 out.writeObject(encodeInvocationArgument(channel, inv, i)) } out.writeObject(inv.getAttachments()) }

5,编解码流程

(1)编码

dubbo源码深度解读之rpc模块

(2)解码

dubbo源码深度解读之rpc模块

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值