第7章 Dubbo 服务暴露流程的设计与实现



    
    
    
    
    
    
    
    
    
    

一、服务暴露简图

serviceexport.png
总体流程:(默认配置情况下)
  1. 首先 ServiceConfig 类拿到对外提供服务的实际类 ref(如:DemoServiceImpl);
  2. 然后通过 JavassistProxyFactory 类的 getInvoker 方法将 ref 封装到一个 AbstractProxyInvoker 实例;
  3. 最后通过 InjvmProtocol(本地暴露)和 DubboProtocol(远程暴露)将AbstractProxyInvoker 实例转换成 InjvmExporter 和 DubboExporter。

注意

  • provider 端的 Invoker 封装了对 ref 的调用逻辑;
  • Exporter 是用于管理 Invoker 的生命周期的。
public interface Invoker extends Node {
    /** get service interface. */
    Class getInterface();
    /** invoke. */
    Result invoke(Invocation invocation) throws RpcException;
}

public interface Exporter {
    /** get invoker. */
    Invoker getInvoker();
    /** unexport. 销毁 Invoker */
    void unexport();
}
image.png
  • 服务暴露第一步,会使用 ProxyFactory#getInvoker(...) 将 ref 封装到 AbstractProxyInvoker 实例中,该实例是在 ProxyFactory#getInvoker(...) 中创建的匿名内部类,并复写了 AbstractProxyInvoker#doInvoker 方法
public abstract class AbstractProxyInvoker implements Invoker {
    // 真实对象 ref, eg. DemoServiceImpl
    private final T proxy;
    // 提供模板方法:1. 调用子类发起请求  2. 包装响应为 RpcResult
    @Override
    public Result invoke(Invocation invocation) throws RpcException {
        return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
    }
    // 子类覆写的真正调用的方法
    protected abstract Object doInvoke(T proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable;
}

public class JavassistProxyFactory extends AbstractProxyFactory {
    @Override
    public  Invoker getInvoker(T proxy, Class type, URL url) {
        // wrapper:通过动态生成一个真实的服务提供者(DemoServiceImpl)的wrapper类,来避免反射调用
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 直接调用wrapper,wrapper底层调用DemoServiceImpl
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
}

这样服务暴露的第一步,我们会得到一个由 JavassistProxyFactory#getInvoker(...) 创建的匿名内部类 AbstractProxyInvoker 实例。

image.png
  • 服务暴露的第二步,会使用 Protocol#export(Invoker invoker) 将第一步得到的 AbstractProxyInvoker 实例封装到 Exporter 中(InvokerExporter 一对一,后续 Exporter 会管理 Invoker 的生命周期,并且作为 Invoker 的门面与外部沟通),我们只看远程暴露,服务暴露第二步之后,会获得一个 DubboExporter 实例
public abstract class AbstractExporter implements Exporter {
    // 封装了 Invoker,用于管理该 Invoker 的生命周期
    private final Invoker invoker;
    @Override
    public Invoker getInvoker() {
        return invoker;
    }
    @Override
    public void unexport() {
        ...
        getInvoker().destroy();
    }
}

public class DubboExporter extends AbstractExporter {
    // serviceKey: group/path:version:port
    private final String key;

    /**
     * 注意:exporterMap 对象实际上持有的是 AbstractProtocol 中的 exporterMap 对象引用
     * key: serviceKey
     * value: 具体的 Exporter 实例,eg. DubboExporter
     */
    private final Map> exporterMap;

    public DubboExporter(Invoker invoker, String key, Map> exporterMap) {
        super(invoker); // 存储该 DubboExporter 实例管理的 Invoker 实例
        this.key = key;
        this.exporterMap = exporterMap;
    }

    @Override
    public void unexport() {
        super.unexport();
        exporterMap.remove(key);
    }
}
image.png
  • RegistryProtocol 实际上是其他具体 Protocol(eg. DubboProtocol)的 AOP 类:
  1. 首先会调用具体 Protocol#export(...)
  2. 之后获取 Registry,然后进行注册,最后监听 override 数据。(这一步的三个操作就是 AOP 的目的)
// 具体 Protocol 的 AOP 类
public class RegistryProtocol implements Protocol {
    // 具体协议
    private Protocol protocol;
    @Override
    public  Exporter export(final Invoker originInvoker) throws RpcException {
        // 1. 做具体的 Protocol 的暴露操作
        ExporterChangeableWrapper exporter = doLocalExport(originInvoker);
        ...
        // 2. 获取注册中心
        Registry registry = getRegistry(originInvoker);
        ...
        // 3. 注册
        register(registryUrl, registeredProviderUrl);
        // 4. 订阅 the override data
        ...
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        //Ensure that a new exporter instance is returned every time export
        return new DestroyableExporter(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);
    }

    private  ExporterChangeableWrapper doLocalExport(Invoker originInvoker) {
        ...
        // 调用具体 Protocol 暴露服务
        protocol.export(invokerDelegete);
        ...
        return exporter;
    }
    ...
}

public abstract class AbstractProtocol implements Protocol {
    /**
     * 该容器是当请求到来时获取 Exporter 的地方
     * key: serviceKey
     * value: 具体的 Exporter 实例,eg. DubboExporter
     */
    protected final Map> exporterMap = new ConcurrentHashMap>();
    ...
}

public class DubboProtocol extends AbstractProtocol {
    @Override
    public  Exporter export(Invoker invoker) throws RpcException {
        ...
        // 获取 serviceKey:group/path:version:port
        String key = serviceKey(url);
        // 将 invoker 存储到 DubboExporter 中,并且让 DubboExporter 持有 AbstractProtocol#exporterMap 的对象引用(后续 DubboExporter 在做销毁操作时,会主动从该 exporterMap 中删除对象,做到逻辑高内聚)
        DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
        // 将 {serviceKey:具体的Exporter} 存储到 AbstractProtocol#exporterMap 中,当请求到来时,来这里根据 serviceKey 获取 Exporter
        exporterMap.put(key, exporter);
        ...
        // 开启 netty 服务
        openServer(url);
        ...
        return exporter;
    }

    // 真正的 netty 请求处理器
    private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
        @Override
        public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
            if (message instanceof Invocation) {
                Invocation inv = (Invocation) message;
                // 当请求到来时,找到真正要处理请求的那个Invoker
                Invoker invoker = getInvoker(channel, inv); 
                ...
                // 发起调用
                return invoker.invoke(inv);
            }
            throw new RemotingException(...);
        }

        // 接收到请求时的处理逻辑
        @Override
        public void received(Channel channel, Object message) throws RemotingException {
            if (message instanceof Invocation) {
                reply((ExchangeChannel) channel, message);
            } else {
                ...
            }
        }
        ...
    };

    /**
     * 当请求到来时,找到真正要处理请求的那个Invoker
     * 1. 首先根据请求参数 Channel channel, Invocation inv 组装 serviceKey=group/path:version:port
     * 2. 根据 serviceKey 从 ExporterMap 中获取 Exporter
     * 3. 从Exporter 中获取 Invoker
     */
    Invoker getInvoker(Channel channel, Invocation inv) throws RemotingException {
        ...
        /**
         * 1. 根据请求参数 Channel channel, Invocation inv 组装 serviceKey=group/path:version:port
         *    port 从 Channel 中获取;path、version、group 从 Invocation 中获取
         */
        int port = channel.getLocalAddress().getPort();
        String path = inv.getAttachments().get(Constants.PATH_KEY);
        ...
        // group/path:version:port
        String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));
        /**
         * 2. 从 exporterMap 中获取 Exporter
         */
        DubboExporter exporter = (DubboExporter) exporterMap.get(serviceKey);

        if (exporter == null)
            throw new RemotingException(...);
        /**
         * 3. 从Exporter 中获取 Invoker
         */
        return exporter.getInvoker();
    }
}

整个流程:当 netty 接收到一个请求时

  1. 首先根据请求参数 Channel channel, Invocation inv 组装 serviceKey=group/path:version:port
  2. 根据 serviceKey 从 AbstractProtocol#exporterMap 中获取 Exporter(DubboExporter 实例,服务暴露第二步做了存储)
  3. 从 Exporter 中获取 Invoker(AbstractInvoker 实例,服务暴露第二步做了存储)
  4. 调用 Invoker#invoke(...) 调用对应的 ref.xxxmethod(...)(服务暴露第一步做了初始化)

二、服务暴露源码梯形图

ServiceBean.onApplicationEvent(ApplicationEvent event)
-->ServiceConfig.export()
  -->doExport()
    -->doExportUrls()
      -->doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs)
        
        -->exportLocal(url)
          //1.1 将实现类ref封装成Invoker
          -->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
             proxy:DemoServiceImpl实例(即ref实例) 
             type:interface com.alibaba.dubbo.demo.DemoService  
             url:injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3141&side=provider×tamp=1510021401013
            -->Wrapper.getWrapper(Class DemoServiceImpl)
            -->new AbstractProxyInvoker(proxy, type, url)
          //1.2 将实现类Invoker暴露为Exporter
          -->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
             组建invoker链,实际上只有最后一个是真正的AbstractProxyInvoker实例,前边的都是filter。
             invoker:AbstractProxyInvoker实例 
             key:service.filter 
             group:provider
          -->InjvmProtocol.export(Invoker invoker)
             invoker:经过filter包装的invoker
            -->new InjvmExporter(Invoker invoker, String key, Map> exporterMap)
               invoker:经过filter包装的invoker 
               key:com.alibaba.dubbo.demo.DemoService 
               exporterMap:传入时为空,构造器执行后为{"com.alibaba.dubbo.demo.DemoService", 当前的InjvmExporter实例}
          -->List> exporters.add(上述的exporter)
        
        //2.1 将实现类ref封装成Invoker
        -->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
           proxy:DemoServiceImpl实例(即ref实例) 
           type:interface com.alibaba.dubbo.demo.DemoService
          -->Wrapper.getWrapper(Class DemoServiceImpl)
          -->new AbstractProxyInvoker(proxy, type, url)
        -->RegistryProtocol.export(final Invoker originInvoker)
           originInvoker:上述的AbstractProxyInvoker实例
          //2.2 将invoker转化为exporter
          -->doLocalExport(originInvoker)
            -->new InvokerDelegete(Invoker invoker, URL url)
               invoker:原始的AbstractProxyInvoker实例
            -->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
               组建invoker链,实际上只有最后一个是真正的InvokerDelegete实例,前边的都是filter
               invoker:InvokerDelegete实例 
               key:service.filter 
               group:provider
            -->DubboProtocol.export(Invoker invoker)
               invoker:经过filter包装的InvokerDelegete实例
              -->new DubboExporter(Invoker invoker, String key, Map> exporterMap)
                 invoker:经过filter包装的InvokerDelegete实例 
                 key:com.alibaba.dubbo.demo.DemoService:20880 (group/path:version:port)
                 exporterMap:传入时为空,构造器执行后又执行了put,为{"com.alibaba.dubbo.demo.DemoService:20880", 当前的DubboExporter实例}
              //2.3 开启netty服务端监听客户端请求
              -->openServer(URL url)
                -->createServer(URL url)
                    -->HeaderExchanger.bind(URL url, ExchangeHandler handler)
                       handler:DubboProtocol.requestHandler
                      -->new DecodeHandler(new HeaderExchangeHandler(handler)))
                        -->NettyTransporter.bind(URL url, ChannelHandler listener)
                           listener:上边的DecodeHandler实例
                          -->new NettyServer(URL url, ChannelHandler handler)
                            -->ChannelHandler.wrapInternal(ChannelHandler handler, URL url)
                               handler:上边的DecodeHandler实例
                              -->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
                            -->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
                            -->doOpen()//开启netty服务
                      -->new HeaderExchangeServer(Server server)
                         server:上述的NettyServer
                        -->startHeatbeatTimer()
            -->new ExporterChangeableWrapper(Exporter exporter, Invoker originInvoker)
               exporter:上述的DubboExporter实例  
               originInvoker:原始的AbstractProxyInvoker实例
          //2.4 创建Registry:创建zkclient,连接zk
          -->getRegistry(final Invoker originInvoker)
            -->AbstractRegistryFactory.getRegistry(URL url)
              -->ZookeeperRegistryFactory.createRegistry(URL url)
                -->new ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter)
                  -->ZkclientZookeeperTransporter.connect(URL url)
                    -->new ZkclientZookeeperClient(URL url)
                      -->new ZkClient(url.getBackupAddress())//这里是10.211.55.5:2181
            -->AbstractRegistryFactory.Map REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
          //2.5 向注册中心注册服务
          -->registry.register(registedProviderUrl)
            -->ZookeeperRegistry.doRegister(URL url)
              -->AbstractZookeeperClient.create(String path, boolean ephemeral)
          //2.6 订阅override数据
          -->ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener)
          //2.7 创建新的Exporter实例
          -->new Exporter()//包含了上边的ExporterChangeableWrapper exporter实例 + ZookeeperRegistry实例

服务暴露的实机:默认为spring发布上下文刷新事件时。

默认情况下,整个服务暴露会发生本地暴露远程暴露两次暴露。

2.1 本地暴露

1. 使用 JavassistProxyFactory 将实现类 ref(DemoServiceImpl)封装成AbstractProxyInvoker实例
          1.1 将实现类ref封装成Invoker
          -->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
             proxy:DemoServiceImpl实例(即ref实例) 
             type:interface com.alibaba.dubbo.demo.DemoService  
             url:injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3141&side=provider×tamp=1510021401013
            -->Wrapper.getWrapper(Class DemoServiceImpl)
            -->new AbstractProxyInvoker(proxy, type, url)

看一下核心代码:

public class JavassistProxyFactory extends AbstractProxyFactory {
    ......
    public  Invoker getInvoker(T proxy, Class type, URL url) {
        // 创建 wrapper 实例
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        // 创建 Invoker 实例
        return new AbstractProxyInvoker(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // Invoker 调用 wrapper,wrapper 调用 proxy(即 ref,eg. DemoServiceImpl)
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
}

注意:在 JavassistProxyFactory#getInvoker 中,首先根据 ref 生成一个 Wrapper,之后将 wrapper 封装在 AbstractProxyInvoker 类中。看一下这个 Wrapper 类的核心代码(com.alibaba.dubbo.common.bytecode.Wrapper0,该类是通过 javassist 生成的)。

package com.alibaba.dubbo.common.bytecode;

import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.NoSuchMethodException;
import com.alibaba.dubbo.common.bytecode.NoSuchPropertyException;
import com.alibaba.dubbo.common.bytecode.Wrapper;
import com.alibaba.dubbo.demo.DemoService;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class Wrapper0 extends Wrapper implements ClassGenerator.DC {
    ...
    /**
     * @param object 实现类ref,eg. DemoServiceImpl
     * @param string 方法名称
     * @param arrclass 参数类型
     * @param arrobject 参数值
     * @return 调用返回值
     * @throws java.lang.reflect.InvocationTargetException
     */
    public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException {
        DemoService demoService;
        try {
            demoService = (DemoService)object;
        } catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        try {
            if ("sayHello".equals(string) && arrclass.length == 1) {
                return demoService.sayHello((String)arrobject[0]);
            }
        } catch (Throwable throwable) {
            throw new InvocationTargetException(throwable);
        }
        throw new NoSuchMethodException(new StringBuffer().append("Not found method \"").append(string).append("\" in class com.alibaba.dubbo.demo.DemoService.").toString());
    }
    ...
}

Dubbo 通过“硬编码”的方式(实际上是 Javassist 动态生成)生成一个 wrapper 类,在 wrapper 类内部又调用了具体实现类的具体方法,通过这样的方式避免了反射调用。

2. 使用 ProtocolFilterWrapper 将 AbstractProxyInvoker 实例进行 Filter 链的包装,之后使用 InjvmProtocol 暴露为 InjvmExporter 实例
          //1.2 将实现类Invoker暴露为Exporter
          -->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
             组建invoker链,实际上只有最后一个是真正的AbstractProxyInvoker实例,前边的都是filter。
             invoker:AbstractProxyInvoker实例 
             key:service.filter 
             group:provider
          -->InjvmProtocol.export(Invoker invoker)
             invoker:经过filter包装的invoker
            -->new InjvmExporter(Invoker invoker, String key, Map> exporterMap)
               invoker:经过filter包装的invoker 
               key:com.alibaba.dubbo.demo.DemoService 
               exporterMap:传入时为空,构造器执行后为{"com.alibaba.dubbo.demo.DemoService", 当前的JvmExporter实例}
          -->List> exporters.add(上述的exporter)

这里首先使用 Dubbo SPI 机制,获取到了相应的 filter,之后使用这些 filter 对 AbstractProxyInvoker 实例进行链式包装。最后通过 InjvmProtocol 将包装后的 AbstractProxyInvoker 实例暴露为 InjvmExporter 实例。(实际上,Exporter 是用于管理 Invoker 的生命周期的)

最终生成的InjvmExporter实例包含如下属性:

key = "com.alibaba.dubbo.demo.DemoService"
exporterMap: { "com.alibaba.dubbo.demo.DemoService" -> 当前的InjvmExporter实例 }
Invoker invoker = 被filter进行递归包裹后的Invoker

到这里,整个本地暴露就完成了。总结一下 整体流程

  1. 首先根据 ref 生成一个 wrapper 类,之后将该 wrapper 类封装到 AbstractProxyInvoker 实例中;
  2. 使用符合条件的 filter 对 AbstractProxyInvoker 进行链式包装,最后将包装后的 AbstractProxyInvoker 实例封装到 InjvmExporter 实例中。

2.2 远程暴露

1. 使用 JavassistProxyFactory 将实现类 ref(DemoServiceImpl)封装成 AbstractProxyInvoker 实例

与本地暴露类似,不再赘述。

        //2.1 将实现类ref封装成Invoker
        -->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
           proxy:DemoServiceImpl实例(即ref实例) 
           type:interface com.alibaba.dubbo.demo.DemoService
          -->Wrapper.getWrapper(Class DemoServiceImpl)
          -->new AbstractProxyInvoker(proxy, type, url)
2. 使用 ProtocolFilterWrapper 将 AbstractProxyInvoker 实例进行 Filter 链的包装,之后使用 DubboProtocol 暴露为 DubboExporter 实例
            -->new InvokerDelegete(Invoker invoker, URL url)
               invoker:原始的AbstractProxyInvoker实例
            -->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
               组建invoker链,实际上只有最后一个是真正的InvokerDelegete实例,前边的都是filter
               invoker:InvokerDelegete实例 
               key:service.filter 
               group:provider
            -->DubboProtocol.export(Invoker invoker)
               invoker:经过filter包装的InvokerDelegete实例
              -->new DubboExporter(Invoker invoker, String key, Map> exporterMap)
                 invoker:经过filter包装的InvokerDelegete实例 
                 key:com.alibaba.dubbo.demo.DemoService:20880 (group/servicename:version:port)
                 exporterMap:传入时为空,构造器执行后又执行了put,为{"com.alibaba.dubbo.demo.DemoService:20880", 当前的DubboExporter实例}

与本地暴露类似,最终得到的DubboExporter实例包含如下属性:

key:com.alibaba.dubbo.demo.DemoService:20880
invoker:“InvokerDelegete的filter对象”(InvokerDelegete只是对AbstractProxyInvoker实例的简单封装)
exporterMap:{ "com.alibaba.dubbo.demo.DemoService:20880" -> 当前的DubboExporter实例 }

实际上key的完整值为:group/path:version:port(如果都配置了的话)。

注意:最后在 DubboProtocol 的属性 Map> exporterMap 中也会存储 { key -> 当前的 DubboExporter 实例 },将来 Nettyhandler 会根据 consumer 的请求参数组建 key,然后从这个 exporterMap 中寻找 Exporter 实例,然后从 Exporter 实例中获取相关的被 filter 链包装的 AbstractProxyInvoker 实例,进行调用。

3. 开启 Netty 服务端监听客户端请求
              //2.3 开启netty服务端监听客户端请求
              -->openServer(URL url)
                -->createServer(URL url)
                    -->HeaderExchanger.bind(URL url, ExchangeHandler handler)
                       handler:DubboProtocol.requestHandler
                      -->new DecodeHandler(new HeaderExchangeHandler(handler)))
                        -->NettyTransporter.bind(URL url, ChannelHandler listener)
                           listener:上边的DecodeHandler实例
                          -->new NettyServer(URL url, ChannelHandler handler)
                            -->ChannelHandler.wrapInternal(ChannelHandler handler, URL url)
                               handler:上边的DecodeHandler实例
                              -->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
                            -->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
                            -->doOpen()//开启netty服务
                      -->new HeaderExchangeServer(Server server)
                         server:上述的NettyServer
                        -->startHeatbeatTimer()

这里首先构建并创建各种 handler,层层包装 DubboProtocol.requestHandler 实例(该实例就是 Netty 最终用来处理业务逻辑的那个 handler)。然后启动 Netty 服务端。最后启动心跳。

这里说一下 心跳机制

  • provider:Dubbo 的心跳默认是在 60s 内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,provider 会关闭 channel。(用于回收资源,会执行 Netty 的 channel 的优雅关闭操作)
  • consumer:Dubbo 的心跳默认是在 60s 内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,consumer会进行重连。
4. 创建 Registry:创建zkclient,连接zk
          //2.4 创建Registry:创建zkclient,连接zk
          -->getRegistry(final Invoker originInvoker)
            -->AbstractRegistryFactory.getRegistry(URL url)
              -->ZookeeperRegistryFactory.createRegistry(URL url)
                -->new ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter)
                  -->ZkclientZookeeperTransporter.connect(URL url)
                    -->new ZkclientZookeeperClient(URL url)
                      -->new ZkClient(url.getBackupAddress())//这里是10.211.55.5:2181
            -->AbstractRegistryFactory.Map REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
5. 向注册中心注册服务
          //2.5 向注册中心注册服务
          -->registry.register(registedProviderUrl)
            -->ZookeeperRegistry.doRegister(URL url)
              -->AbstractZookeeperClient.create(String path, boolean ephemeral)

注册完成之后,就会在 zk 上创建节点(url 解码后如下):

/dubbo
- /com.alibaba.dubbo.demo.DemoService
-- /providers
--- /dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3508&side=provider×tamp=1510023456461
6.订阅 override 数据
          //2.6 订阅 override 数据
          -->ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener)

override 数据是用于做配置覆盖的(改变的是 /dubbo/servicekey/configurators 节点),实现 “热配置” 功能。

到这里,远程暴露也就完成了。

流程总结

  1. 首先根据 ref 生成一个 wrapper 类,之后将该 wrapper 类封装到 AbstractProxyInvoker 实例中;
  2. 使用符合条件的 filter 对 AbstractProxyInvoker 进行链式包装,最后将包装后的 AbstractProxyInvoker 实例封装到 DubboExporter 实例(DubboExporter 用于管理 AbstractProxyInvoker 实例的生命周期)中;
  3. 开启 Netty 服务端监听客户端请求;
  4. 创建 zkclient,连接 zk;
  5. 向注册中心注册服务;
  6. 订阅 override 数据。

你可能感兴趣的:(第7章 Dubbo 服务暴露流程的设计与实现)