dubbo源码深度解读五之rpc模块

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

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

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

public interface Invoker<T> extends Node {
     

    Class 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  attachments;

    private transient Invoker invoker;
}

其实也只是提供了Invocation所需的参数而已。我们把目光又放回Invoker。
Invoker的执行过程分为三种类型
(1)本地执行类的Invoker
(2)远程通信执行类的Invoker
(3)多个(2)的Invoker聚合成的集群版的Invoker(需要设计到负载均衡)

dubbo源码深度解读五之rpc模块_第1张图片

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

@SPI("javassist")
public interface ProxyFactory {
     

    //针对client端,创建出代理对象
    @Adaptive({Constants.PROXY_KEY})
     T getProxy(Invoker invoker) throws RpcException;

    //针对server端,将服务对象包装成一个Invoker对象
    @Adaptive({Constants.PROXY_KEY})
     Invoker getInvoker(T proxy, Class type, URL url) throws RpcException;

}

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

3,Protocol
我们发布服务的第一个过程是将服务封装成一个本地执行的invoker,执行服务这个就是执行这个invoker(调用这个invoker的invoke方法),通过反射执行。但是我们看到invoke方法的参数-invocation,这个参数是如何得来的?
服务端的Protocol需要根据指定的协议对外公布服务,当客户端根据协议调用这个服务时候,将用户传递的invocation参数交给invoker来执行,所以Protocol加入了远程通信协议这一块,根据用户的请求获取参数Invocation。

@Extension("dubbo")
public interface Protocol {
     

    int getDefaultPort();

    //针对server端来说,将本地执行类的Invoker通过协议暴漏给外部。这样外部就可以通过协议发送执行参数Invocation,然后交给本地Invoker来执行
    @Adaptive
     Exporter export(Invoker invoker) throws RpcException;

    //这个是针对客户端的,客户端从注册中心获取服务器端发布的服务信息
    //通过服务信息得知服务器端使用的协议,然后客户端仍然使用该协议构造一个Invoker。这个Invoker是远程通信类的Invoker。
    //执行时,需要将执行信息通过指定协议发送给服务器端,服务器端接收到参数Invocation,然后交给服务器端的本地Invoker来执行
    @Adaptive
     Invoker refer(Class type, URL url) throws RpcException;

    void destroy();

}

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

Exporter exporter = protocol.export(invoker);

暴露过程即根据invoker的URL的配置信息来最终选择Protocol实现,默认是dubbo,扩展实现即DubboProtocol,然后再对DubboProtocol进行依赖注入,进行wrap包装。先来看看Protocol的实现情况:
dubbo源码深度解读五之rpc模块_第2张图片

可以看到在返回DubboProtocol之前,经过了ProtocolFilterWrapper(核心方法是buildInvokerChain,构建Chain)、ProtocolListenerWrapper、RegistryProtocol的包装。
包装时候的是装饰模式,类似AOP功能

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  Exporter export(Invoker invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter exporter = new DubboExporter(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

 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);
            }
        }
    }

首先根据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 {

    Invoker getInvoker();

    void unexport();

}

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

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

2,header
dubbo源码深度解读五之rpc模块_第3张图片

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; i < args.length; i++){
     
            out.writeObject(encodeInvocationArgument(channel, inv, i));
        }
        out.writeObject(inv.getAttachments());
    }

5,编解码流程
(1)编码
dubbo源码深度解读五之rpc模块_第4张图片
(2)解码
dubbo源码深度解读五之rpc模块_第5张图片

你可能感兴趣的:(dubbo,dubbo,源码)