前面两节,dubbo准备好了配置了,那么接下来就可以进行服务的暴露了,暴露的代码在RegistryProtocol#export中,RegistryProtocol这个协议会执行暴露,然后执行注册。

public <T> Exporter<T> com.alibaba.dubbo.registry.integration.RegistryProtocol#export(final Invoker<T> originInvoker) throws RpcException {
    //export invoker
    //暴露
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

    。。。。。。省略部分注册代码
    //Ensure that a new exporter instance is returned every time export
    return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);
}

本地暴露

private <T> ExporterChangeableWrapper<T> com.alibaba.dubbo.registry.integration.RegistryProtocol#doLocalExport(final Invoker<T> originInvoker) {
    //获取key,这个key是提供者url地址,按照我们上面配置例子,那么这里的key的值就是
    //dubbo://192.168.56.1:20880/com.dubbo.service.UserService?anyhost=true&application=hello-world-app&bean.name=com.dubbo.service.UserService
    //&bind.ip=192.168.56.1&bind.port=20880&dubbo=2.0.2&generic=false&interface=com.dubbo.service.UserService&methods=sayHello
    //&pid=26392&side=provider&timestamp=1567943599518
    String key = getCacheKey(originInvoker);
    //从缓存中获取已经暴露的包装对象,如果不存在,则需要暴露
    ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
    if (exporter == null) {
        synchronized (bounds) {
            //双重检查
            exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
            if (exporter == null) {
                //创建提供者Invoker,这个Invoker与原始的originInvoker相比,其对应url变成了提供者的url地址
                //dubbo://192.168.56.1:20880/com.dubbo.service.UserService?...
                final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
                //这里这个protocol是dubbo通过spi生成的一个类,它的名字叫做Protocol$Adaptive,它的方法内部会调用ExtensLoader去寻找能够符合
                //条件的协议,我们例子中设置的提供者协议是dubbo,所以这里最终调用的协议是DubboProtocol
                //这里的ExporterChangeableWrapper对象,主要是维护Exporter,与原始Invoker的关系,同时提供了unexport的方法用于取消服务的暴露
                exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                //缓存
                bounds.put(key, exporter);
            }
        }
    }
    return exporter;
}

以下代码就是Adaptive类型的类去寻找适合处理当前协议的export方法

public com.alibaba.dubbo.rpc.Exporter com.alibaba.dubbo.rpc.Protocol$Adaptive#export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
    //invoker对象,就是我们上面创建的InvokerDelegete方法
    if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
    if (arg0.getUrl() == null)
        throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
    //提供者url
    com.alibaba.dubbo.common.URL url = arg0.getUrl();
    //很明显我们在配置例子中设置的暴露协议就是dubbo
    String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
    if (extName == null)
        throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    //此处通过spi去获取合适的协议处理,很显然合适的处理就是DubboProtocol,但是Protocol还实现了三个装饰器
    //他们分别为ProtocolListenerWrapper,ProtocolFilterWrapper,QosProtocolWrapper
    //这个装饰器会依次包装ProtocolListenerWrapper,ProtocolFilterWrapper,QosProtocolWrapper,DubboProtocol
    com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    return extension.export(arg0);
}

ProtocolListenerWrapper.export

public <T> Exporter<T> com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper#export(Invoker<T> invoker) throws RpcException {
    //是否registry协议,如果是将会先暴露,在进行注册
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    //创建了一个ListenerExporterWrapper,看下它的构造方法
    //(*1*),可以发现在创建ListenerExporterWrapper的时候就会触发暴露事件,如果再查看一下它的取消暴露方法,会触发取消暴露事件
    //ExtensionLoader.getExtensionLoader(ExporterListener.class)方法去构建了
    return new ListenerExporterWrapper<T>(protocol.export(invoker),
            //获取暴露的监听器与被@Activate标注且符合条件的监听器,spi
            //部分的代码我们将在分析SPI的时候分析
            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}

//(*1*)
public ListenerExporterWrapper(Exporter<T> exporter, List<ExporterListener> listeners) {
    if (exporter == null) {
        throw new IllegalArgumentException("exporter == null");
    }
    this.exporter = exporter;
    this.listeners = listeners;
    //循环调用监听器,触发暴露事件
    if (listeners != null && !listeners.isEmpty()) {
        RuntimeException exception = null;
        for (ExporterListener listener : listeners) {
            if (listener != null) {
                try {
                    listener.exported(this);
                } catch (RuntimeException t) {
                    logger.error(t.getMessage(), t);
                    exception = t;
                }
            }
        }
        if (exception != null) {
            throw exception;
        }
    }
}

ProtocolFilterWrapper#export

public <T> Exporter<T> com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#export(Invoker<T> invoker) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    //创建过滤器链,一看就是构建了一个责任链
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}

构建过滤器链

private static <T> Invoker<T> com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    //获取符合条件的过滤器,与获取暴露监听器是一样的逻辑,不过对于提供者的group,默认是provider,消费者的就是consumer
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    if (!filters.isEmpty()) {
        //倒序遍历
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {

                @Override
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }

                @Override
                public URL getUrl() {
                    return invoker.getUrl();
                }

                @Override
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }

                @Override
                public Result invoke(Invocation invocation) throws RpcException {
                    //调用拦截器
                    return filter.invoke(next, invocation);
                }

                @Override
                public void destroy() {
                    invoker.destroy();
                }

                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}

形成了一个如下图的链条

在这里插入图片描述

QosProtocolWrapper#export

public <T> Exporter<T> com.alibaba.dubbo.qos.protocol.QosProtocolWrapper#export(Invoker<T> invoker) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        //用于启动命令服务,可以通过telnet命令查看消费者,提供者
        //默认端口是2222
        startQosServer(invoker.getUrl());
        return protocol.export(invoker);
    }
    //暴露
    return protocol.export(invoker);
}
public <T> Exporter<T> com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#export(Invoker<T> invoker) throws RpcException {
    //获取提供者暴露地址
    URL url = invoker.getUrl();

    // export service.
    //group/serviceName:serviceVersion:端口
    String key = serviceKey(url);
    //创建Dubbo协议暴露者,维护这Invoker,key,exporterMap<key, Exporter>之间的关系
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    exporterMap.put(key, exporter);

    //export an stub service for dispatching 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);
    //优化序列化
    //如果配置了SerializationOptimizer,那么会进行注册
    //在序列化的时候就可以从SerializableClassRegistry的一个静态Map中获取
    optimizeSerialization(url);
    return exporter;
}

DubboProtocol#openServer

private void com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer(URL url) {
    // find server.
    //获取地址
    //ip:port
    String key = url.getAddress();
    //client can export a service which's only for server to invoke
    boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
    if (isServer) {
        //从缓存中获取
        ExchangeServer server = serverMap.get(key);
        if (server == null) {
            //创建ExchangeServer
            serverMap.put(key, createServer(url));
        } else {
            // server supports reset, use together with override
            server.reset(url);
        }
    }
}

创建ExchangeServer

private ExchangeServer com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer(URL url) {
    // send readonly event when server closes, it's enabled by default
    //添加通道只读参数
    url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
    // enable heartbeat by default
    //添加心跳周期参数
    url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
    //使用netty还是mina等Transporter
    String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);
    //是否存在对应的Transporter extension
    if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
        throw new RpcException("Unsupported server type: " + str + ", url: " + url);
    //添加参数,codec -》 dubbo,用于激活筛选,在前面的监听器和过滤器都使用到了这样的筛选条件
    //比如@Adaptive({Constants.CODEC_KEY})
    url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
    ExchangeServer server;
    try {
        //(*1*)
        server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
        throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    }
    str = url.getParameter(Constants.CLIENT_KEY);
    if (str != null && str.length() > 0) {
        Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
        if (!supportedTypes.contains(str)) {
            throw new RpcException("Unsupported client type: " + str);
        }
    }
    return server;
}

//(*1*)
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    if (handler == null) {
        throw new IllegalArgumentException("handler == null");
    }
    url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
    return getExchanger(url).bind(url, handler);
}
                            |
                            V
public static Exchanger getExchanger(URL url) {
    //Constants.EXCHANGER_KEY = exchanger, Constants.DEFAULT_EXCHANGER = header
    String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);
    return getExchanger(type);
}
                            |
                            V
public static Exchanger getExchanger(String type) {
    //因为没有指定exchanger参数,所以返回的Exchanger是HeaderExchanger
    return ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
}

HeaderExchanger的bind方法

public ExchangeServer HeaderExchanger#bind(URL url, ExchangeHandler handler) throws RemotingException {
    //创建HeaderExchangeServer对象,在这个类的构造器中还进行心跳的启动
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

public HeaderExchangeServer(Server server) {
    if (server == null) {
        throw new IllegalArgumentException("server == null");
    }
    this.server = server;
    //获取心跳周期
    this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
    //超时时间默认是心跳周期的三倍
    this.heartbeatTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
    //如果超时间少于心跳周期的2倍,抛错
    if (heartbeatTimeout < heartbeat * 2) {
        throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
    }
    //启动心跳
    startHeartbeatTimer();
}

private void startHeartbeatTimer() {
    //先关掉可能已经启动的心跳,避免造成内存泄露和驻留无法关闭的心跳
    stopHeartbeatTimer();
    if (heartbeat > 0) {
        //启动任务调度
        heartbeatTimer = scheduled.scheduleWithFixedDelay(
                new HeartBeatTask(new HeartBeatTask.ChannelProvider() {
                    @Override
                    public Collection<Channel> getChannels() {
                        return Collections.unmodifiableCollection(
                                HeaderExchangeServer.this.getChannels());
                    }
                }, heartbeat, heartbeatTimeout),
                heartbeat, heartbeat, TimeUnit.MILLISECONDS);
    }
}

public void com.alibaba.dubbo.remoting.exchange.support.header.HeartBeatTask#run() {
    try {
        long now = System.currentTimeMillis();
        for (Channel channel : channelProvider.getChannels()) {
            if (channel.isClosed()) {
                continue;
            }
            try {
                Long lastRead = (Long) channel.getAttribute(
                        HeaderExchangeHandler.KEY_READ_TIMESTAMP);
                Long lastWrite = (Long) channel.getAttribute(
                        HeaderExchangeHandler.KEY_WRITE_TIMESTAMP);
                if ((lastRead != null && now - lastRead > heartbeat)
                        || (lastWrite != null && now - lastWrite > heartbeat)) {
                    //发送心跳
                    Request req = new Request();
                    req.setVersion(Version.getProtocolVersion());
                    req.setTwoWay(true);
                    req.setEvent(Request.HEARTBEAT_EVENT);
                    channel.send(req);
                  。。。。。。省略日志
                }
                //心跳超时
                if (lastRead != null && now - lastRead > heartbeatTimeout) {
                    //如果是客户端通道,尝试重连
                    if (channel instanceof Client) {
                        try {
                            //重连
                            ((Client) channel).reconnect();
                        } catch (Exception e) {
                            //do nothing
                        }
                    } else {
                        //服务通道挂了,没得说,关闭
                        channel.close();
                    }
                }
            } catch (Throwable t) {
                logger.warn("Exception when heartbeat to remote channel " + channel.getRemoteAddress(), t);
            }
        }
    } catch (Throwable t) {
        logger.warn("Unhandled exception when heartbeat, cause: " + t.getMessage(), t);
    }
}

我们继续看到Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))

//HeaderExchangeHandler:在每次通道动作中都会进行记录时间,以便心跳能够进行时间判断
//DecodeHandler:解码处理,当接收消息的时候会对消息进行解码
//handler:这个是在DubboProtocol中定义的一个内部类,对于这个对象,我们等会会分析它的reply方法
Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))


public Server com.alibaba.dubbo.remoting.transport.netty4.NettyTransporter#bind(URL url, ChannelHandler listener) throws RemotingException {
    return new NettyServer(url, listener);
}

                |
                V
public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
    //url:提供者URL, ExecutorUtil.setThreadName:设置线程池名字,
    super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}

//其中ChannelHandlers.wrap最终调用了以下方法
protected ChannelHandler com.alibaba.dubbo.remoting.transport.dispatcher.ChannelHandlers#wrapInternal(ChannelHandler handler, URL url) {
    //首先通过spi的方式创建了AllChannelHandler,这个是一个带有线程池的通道处理器,它由AllDispatcher分发器创建
    //再次被HeartbeatHandler装饰,它的作用就是通道每个动作都会发生时间的更新,断连时清除时间
    //最后被MultiMessageHandler装饰,它的作用就是用于处理一次性传递多个message的情况
    return new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class)
            .getAdaptiveExtension().dispatch(handler, url)));
}

继续分析NettyServer的构造

public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
    //url:提供者URL, ExecutorUtil.setThreadName:设置线程池名字,
    super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}
                                    |
                                    V
public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
    super(url, handler);
    //ip:port
    localAddress = getUrl().toInetSocketAddress();
    //获取需要绑定的主机地址
    String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());
    //端口
    int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());
    if (url.getParameter(Constants.ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {
        bindIp = NetUtils.ANYHOST;
    }
    bindAddress = new InetSocketAddress(bindIp, bindPort);
    //通道参数,接收队列最大个数
    this.accepts = url.getParameter(Constants.ACCEPTS_KEY, Constants.DEFAULT_ACCEPTS);
    //空闲超时还进
    this.idleTimeout = url.getParameter(Constants.IDLE_TIMEOUT_KEY, Constants.DEFAULT_IDLE_TIMEOUT);
    try {
        //打开通道服务
        doOpen();
        if (logger.isInfoEnabled()) {
            logger.info("Start " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress());
        }
    } catch (Throwable t) {
        throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()
                + " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);
    }
    //fixme replace this with better method
    //数据存储,获取默认的扩展,目前只有一个实现SimpleDataStore
    //它使用ConcurrentMap<String, ConcurrentMap<String, Object>> data =
            new ConcurrentHashMap<String, ConcurrentMap<String, Object>>()
    //存储数据
    DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
    //获取线程池对象
    executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
}
                                    |
                                    V
public AbstractEndpoint(URL url, ChannelHandler handler) {
    super(url, handler);
    this.codec = getChannelCodec(url);
    this.timeout = url.getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
    this.connectTimeout = url.getPositiveParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT);
}
                                    |
                                    V
public AbstractPeer(URL url, ChannelHandler handler) {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    if (handler == null) {
        throw new IllegalArgumentException("handler == null");
    }
    this.url = url;
    this.handler = handler;
}

打开通道服务

protected void com.alibaba.dubbo.remoting.transport.netty4.NettyServer#doOpen() throws Throwable {
    //netty的服务启动类ServerBootstrap
    bootstrap = new ServerBootstrap();
    //boss事件执行循环组
    bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
    //设置工作事件执行循环组
    workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
            new DefaultThreadFactory("NettyServerWorker", true));
    //netty的通道处理
    final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
    channels = nettyServerHandler.getChannels();
    
    bootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
            .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
            .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
            .childHandler(new ChannelInitializer<NioSocketChannel>() {
                //初始化客户端通道时,注册到客户端ChannelPipeline中
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {
                    NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                    ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
                            //添加dubbo的解码器
                            .addLast("decoder", adapter.getDecoder())
                            //添加编码器
                            .addLast("encoder", adapter.getEncoder())
                            //添加通道处理器
                            .addLast("handler", nettyServerHandler);
                }
            });
    // bind
    ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
    channelFuture.syncUninterruptibly();
    channel = channelFuture.channel();

}

下一节我们开始服务的注册