Dubbo漫谈之服务提供端

上一篇的内容,继续Dubbo服务提供端模块的分解,先来回顾下RPC的图:
0
Consumer调用走到网络部分就结束了,下面来分解下图右半部分Dubbo的实现。

Dubbo RPC 服务端组件

还是按照图的顺序自左至右,一个请求跨越了网络,数据走到Provider这一侧。首先自然是反序列化和协议解析,这个跟Consumer端正好是反的,但是代码是一起的,分别是Serialization中的deserialize()方法和Codec2中的decode()方法。 

请求传输

Provider要提供服务,必须在某一端口上监听来接收数据,所以跟Client端对应要有个Server。

Server

为了支持多协议,Dubbo将Server抽象为ExchangeServer接口:
public interface ExchangeServer extends RemotingServer {
    /**
     * 获取所有和client的Channel
     */
    Collection<ExchangeChannel> getExchangeChannels();
    /**
     * 获取指定Client的Channel
     */
    ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress);
}
public interface ExchangeChannel extends Channel {
    /**
     * 发送请求
     */
    CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException;
    /**
     * 接收数据的handler
     */
    ExchangeHandler getExchangeHandler();
    /**
     * 关闭Channel
     */
    @Override
    void close(int timeout);
}
跟上一篇的ExchangeClient一样,ExchangeServer自然也是从Exchanger接口里来的。
@SPI(HeaderExchanger.NAME)
public interface Exchanger {
    /**
     * 开启一个服务端Server
     */
    @Adaptive({Constants.EXCHANGER_KEY})
    ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException;
    /**
     * 获取Client
     */
    @Adaptive({Constants.EXCHANGER_KEY})
    ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException;
}
当然底层还是依赖的Transporter,这里就不再重复说了。Handler 回到数据流上,请求到达后,经过协议解析和对象的反序列化,以Request对象的形式到达ExchangeHandler, 现在看下该接口:
public interface ExchangeHandler extends ChannelHandler, TelnetHandler {
    /**
     * reply.
     */
    CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException;
}
从接口可以看到,在收到请求后,handler负责回复Response,就是说handler负责调用接口的实现类,然后将结果通过网络返回。

服务暴露

请求到达服务端后,需要调用本地的接口实现类。还记得上一篇中讲到的Invoker吗?它是对调用的封装接口,在服务提供方,同样是用的它,只是这次执行invoke()方法的时候是调用的本地实现类。

Exporter

Invoker调用本地方法,首要的自然是找到本地实现类在什么地方,这时候就需要引入另外一个接口Exporter。
public interface Exporter<T> {
    /**
     * 获取Invoker
     */
    Invoker<T> getInvoker();
    /**
     * 取消接口暴露
     */
    void unexport();
} 
Exporter代表本地接口服务的暴露。可以这么理解,本地有个接口的实现,我想让其它服务能够远程调用到,那就需要按照一定的协议注册成一个Exporter,否则即使远程发送请求过来要求访问该实现,Dubbo也是不允许的。 可以看到,通过Exporter是可以拿到Invoker的,对这个invoker的执行调用的就是本地接口实现。Dubbo中一个接口实现可以以多种协议暴露,调用的Protocol接口的export方法,默认自然是DubboProtocol中的DubboExporter。
@SPI("dubbo")
public interface Protocol {
    //暴露服务接口
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

     //获取接口调用的Invoker
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
} 
看完上面几个接口,我们把关系捋一下。在服务启动的后,根据服务的配置,Dubbo会将一个接口的实现在指定的协议上暴露成一个Exporter,Exporter中封装了一个本地调用的Invoker。 ExchangeHandler收到请求后,从请求中拿到协议,接口名、方法名以及反序列化后的参数,所有这些基本上都封装在一个RpcInvocation中。Handler到指定协议中找接口的Exporter,找到后就可以获取到Invoker,invoker执行时会调用本地实现类的方法。

本地调用

上面讲到发起调用本地方法的Invoker,Dubbo也有两种实现方式,一种是用的java的反射调用,一种是用javaassist生成一个Invoker的实现类,在生成的类中直接引用接口实现。显然后一种性能更好,Dubbo默认也是用的后一种方式。 获取Invoker的方法也是在ProxyFactory接口中。
@SPI("javassist")
public interface ProxyFactory {
    /**
     * 创建远程接口的代理,Consumer用
     */
    @Adaptive({PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;
    /**
     * 创建本地调用Invoker的代理,Provider用
     */
    @Adaptive({PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
} 

Provider端总结

一图胜千言,对应RPC的图画下Dubbo Provider这一端的模块关系。
原文地址:https://www.cnblogs.com/johnvwan/p/15647439.html