dubbo源码解析(三): Socket Server和方法调用

来源:互联网 发布:域名转让流程 编辑:程序博客网 时间:2024/06/05 10:01

之前的两篇文章给大家介绍了dubbo的扩展点加载机制以及服务启动的过程
dubbo源码解析(一): 扩展点加载(ExtensionLoader)
dubbo源码解析(二): dubbo服务的启动

本文给大家梳理一下dubbo的socket服务的启动以及一条消息过来后,dubbo框架究竟是怎么处理的。
前文提到,provider服务的暴露最后调用了protocol的export方法

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

这里配置的protocol的类型是dubbo,具体也就是DubboProtocol这个类,我们来看下DubboProtocol的export方法

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);        }    }    //创建socket server    openServer(url);    return exporter;}

url就是上文中提到的provider的一串唯一标识符,包括了服务的ip、端口、别名以及暴露的方法等等。之后对StubSupportEvent和Callbackservice进行一些特殊化处理,这里不做深究,最后就进入到了openServer()方法。

private void openServer(URL url) {    // find server.    String key = url.getAddress();    //client 也可以暴露一个只有server可以调用的服务。    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,配合override功能使用            server.reset(url);        }    }}

getAddress()返回host:port形式的地址,作为server map的key。之后判断服务类型,如果是一个server的话,调用createServer()产生一个新的ExchangeServer,并绑定一个ExchangeHandler

ExchangeServer server;server = Exchangers.bind(url, requestHandler);

其具体类型为HeaderExchangeServer

new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));

调用

getTransporter().bind(url, handler);

这里会涉及到本人dubbo系列第一篇博文的知识点,扩展点加载

    public static Transporter getTransporter() {        return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();    }

加载的是Transporter的自适应扩展点,这里的自适应扩展点返回的是NettyTransporter,之后就是一个正常的netty server了。这里采用的是异步方式,传入的handler是ExchangeHandlerAdapter,当有消息到来时,进入received()方法后调用reply()方式进行回包。

public Object reply(ExchangeChannel channel, Object message) throws RemotingException {    if (message instanceof Invocation) {        Invocation inv = (Invocation) message;        Invoker<?> invoker = getInvoker(channel, inv);        //如果是callback 需要处理高版本调用低版本的问题        if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))){            String methodsStr = invoker.getUrl().getParameters().get("methods");            boolean hasMethod = false;            if (methodsStr == null || methodsStr.indexOf(",") == -1){                hasMethod = inv.getMethodName().equals(methodsStr);            } else {                String[] methods = methodsStr.split(",");                for (String method : methods){                    if (inv.getMethodName().equals(method)){                        hasMethod = true;                        break;                    }                }            }            if (!hasMethod){                logger.warn(new IllegalStateException("The methodName "+inv.getMethodName()+" not found in callback service interface ,invoke will be ignored. please update the api interface. url is:" + invoker.getUrl()) +" ,invocation is :"+inv );                return null;            }        }        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的概念,以下文字摘自dubbo官网:

在Dubbo的核心领域模型中:

Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。
Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
Invocation是会话域,它持有调用过程中的变量,比如方法名,参数等。

Protocol和Invoker的概念我们在上文已经提及过,这里的Invocation封装了rpc调用的MethodName、ParameterTypes、Arguments等参数。这里涉及到的实体类是RpcInvocation,RpcInvocation实现了Serializable,可序列化后进行传输。
我们回到reply()方法,在得到Invocation的实例后,查找对应的Invoker调用invoker.invoke()方法进行回包。
这里有一个获取invoker的过程,在本文最上面的export()函数中,有一步

exporterMap.put(key, exporter);

的操作,这里存储了key所对应的exporter,在reply()方法中,通过getInvoker()获取invoker,具体流程就是构造相应的key之后,从exporterMap获取对应的exporter,再找到所对应的invoker

String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);if (exporter == null)    throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv);return exporter.getInvoker();

到了这一步,就可以通过反射去调用server端的具体方法去回包啦。具体的invoker生成流程可以参见上文。

到这里,整个dubbo服务的启动和运行已经介绍完了,以后有空的话可能会再分析一下dubbo的负载均衡机制以及服务发现机制。

原创粉丝点击