【dubbo源码分析】DubboProvider服务端暴露过程详解

provider服务暴露过程分为两种:
1.发布本地服务【Injvm】,主要供本地环境服务间调用

2.发布远程服务【protocol】,根据注册中心地址列表将服务依次发布到注册中心上。

整体交互图如下:

下面开始讲解本地暴露和远程暴露过程:

1.本地服务暴露(Injvm)
1.1 本地服务 Invoker构建
ServiceConfig.java:
 private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();//InjvmProtocol
    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); // JavassistProxyFactory
    private void exportLocal(URL url) {
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
                    .setHost(LOCALHOST)
                    .setPort(0);
            Exporter<?> exporter = protocol.export(    
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }
从源码可知,本地服务暴露协议头为 Injvm,设置好protocol后直接调用proxyFactory.getInvoker 获取本地服务Invoker,最后通知InjvmProtocol.export发布服务
下面看看 JavassistProxyFactory getInvoker如何工作的:

JavassistProxyFactory.java :
public class JavassistProxyFactory extends AbstractProxyFactory {

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper类不能正确处理带$的类名
//根据class获取Wrapper,接着通过wrapper调用
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

}


Wrapper类是专门生成实例类的 Wrapper包装的工具类,分析getWrapper后得知,最后Wrapper给 com.alibaba.dubbo.demo.provider.DemoServiceImpl生成的wrapper类源代码如下:
com.alibaba.dubbo.common.bytecode.Wrapper1 extends Wrapper implements com.alibaba.dubbo.common.bytecode.ClassGenerator.DC {
	public static String[] pns; // property name array.
	public static java.util.Map pts; // property type map.
	public static String[] mns; // all method name array.  这里等于 [sayHello]
	public static String[] dmns; // declared method name array.  这里等于 [sayHello]
	public static Class[] mts0;// 这里是[class java.lang.String]
	public Wrapper1(){}
	
	public String[] getPropertyNames(){ return pns;  }
	
	public boolean hasProperty(String n){ return pts.containsKey($1); }
	
	public Class getPropertyType(String n){ return (Class)pts.get($1); }
	
	public String[] getMethodNames(){ return mns; }
	
	public String[] getDeclaredMethodNames(){ return dmns; }

	public void setPropertyValue(Object o, String n, Object v){ 
		com.alibaba.dubbo.demo.provider.DemoServiceImpl w; 
		try{ 
			w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl)$1);  // $1 即为入参1
		}catch(Throwable e){ 
			throw new IllegalArgumentException(e); 
		} 
		throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \""+$2+"\" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl."); 
	}

	public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException{ 
		com.alibaba.dubbo.demo.provider.DemoServiceImpl w; 
		try{ 
			w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl)$1);  // $1 即为入参1
		}catch(Throwable e){ 
			throw new IllegalArgumentException(e); 
		} 

		try{ 
			if( "sayHello".equals( $2 )  &&  $3.length == 1 ) {  // $2 即为入参2  $3即为入参3 class[] p
			
				return ($w)w.sayHello((java.lang.String)$4[0]); } 
			} catch(Throwable e) {
				throw new java.lang.reflect.InvocationTargetException(e);  
			} 
			
		throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \""+$2+"\" in class com.alibaba.dubbo.demo.provider.DemoServiceImpl."); 
	}

	public Object getPropertyValue(Object o, String n){ 
		com.alibaba.dubbo.demo.provider.DemoServiceImpl w; 
		try{ 
			w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl)$1); 
		}catch(Throwable e){ 
			throw new IllegalArgumentException(e); 
		} 
		throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \""+$2+"\" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl."); 
	}	
}
最终 JavassistProxyFactory 返回了一个抽象 匿名类 AbstractProxyInvoker
1.2 发布本地服务 export()
Invoker构造完成后开始执行export对invoker进行服务发布:
 protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();//InjvmProtocol
  Exporter<?> exporter = protocol.export(Invoker invoker)    
export的Protocol会根据url的protocol=injvm获取具体的SPI,最终会获取到 InjvmProtocol来处理export;
又因为 Protocol 的SPI包含 Wrapper类【 ProtocolListenerWrapper, 管理Filter链的 ProtocolFilterWrapper】,因此protocol.export()类的调用过程为:
ProtocolListenerWrapper .export(invoker)
-> ProtocolFilterWrapper .export(invoker) //这一步会将所有Provider端的FIlter链加载并构建出基于Filter链调用的Invoker【 最后构建成 EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter -> TraceFilter -> MonitorFilter -> TimeoutFilter -> ExceptionFilter -> 具体的Invoker 链】如下图:
-> InjvmProtocol.export(invoker) // 这里的invoker是包含了Filter链的Invoker
InjvmProtocol 最终根据传入的 Invoker,待发布的服务名称【如 com.alibaba.dubbo.demo.DemoService】构建实例 InjvmExporter:
InjvmProtocol.export():
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }
InjvmExporter .java
 InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
        super(invoker);
        this.key = key;
        this.exporterMap = exporterMap;
        exporterMap.put(key, this);
    }
至此,本次服务构建并发布完成。
2.远程服务暴露(基于注册中心)
这里主要介绍基于 zookeeper的远程服务暴露,
分两步走:
2.1远程服务Invoker创建
2.2发布服务 exporter
2.1 远程服务 Invoker构建

先看源码。ServiceConfig.java
for (URL registryURL : registryURLs) {
                            url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
由源码可知服务端在获取到注册中心地址列表后,迭代该列表, 并设置monitor地址【服务监控地址】, export地址【要暴露的服务地址】,接着通过proxtFactory 【JavassistProxyFactory】获取invoker,
最终通过 protocol【url.protocol=registry;因此 protocol = RegistryProtocol】来对服务进行发布【export】
这里注册中心地址列表 registryURL为:
[
registry://10.0.28.54:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=6720&registry=zookeeper×tamp=1521712841397, 
registry://10.0.28.54:2182/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=6720&registry=zookeeper×tamp=1521712841397, 
registry://10.0.28.54:2183/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=6720&registry=zookeeper×tamp=1521712841397
]
proxyFactory.getInvoker(ref,class,url) 依旧通过JavassistProxyFactory构建Invoker(同1本地服务暴露构建Invoker一直,返回的是新构建的 AbstractProxyInvoker 匿名类,其中 AbstractProxyInvoker 内wrapper 为同一个实例)
此时构建成功的Invoker内的url为包含了export参数的url:
registry://10.0.28.54:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo%3A%2F%2F10.0.28.54%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D10.0.28.54%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D6720%26side%3Dprovider%26timestamp%3D1521713776074&pid=6720&registry=zookeeper×tamp=1521712841397
到这 第一个注册地址 invoker 创建完毕。
2.2 发布远端服务 export()

交互流程如下:
依据日志:
Register dubbo service com.alibaba.dubbo.demo.DemoService url 
dubbo://10.0.28.54:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=10.0.28.54&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=8956&side=provider×tamp=1522035115024 
to registry 
registry://10.0.28.54:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=8956&registry=zookeeper×tamp=1522035107435, dubbo version: 2.0.0, current host: 127.0.0.1
来跟踪服务DemoService是如何注册到 zk【10.0.28.54:2181】的。

由于当前url.protocol = registry,因此最终的export发布任务交由RegistryProtocol来处理,
又因为 Protocol 的SPI包含 Wrapper类【 ProtocolListenerWrapper, 管理Filter链的 ProtocolFilterWrapper】,因此protocol.export()类的调用过程为:
 
  
ProtocolListenerWrapper.export(invoker) -> ProtocolFilterWrapper.export(invoker) ->RegistryProtocol.export()
接下来我们看看 RegistryProtocol .export 源码:
export主要干了几件事:
2.2.1.构建Exporter
2.2.2.根据registryUrl获取Registry
2.2.3.registry中注册节点
2.2.4.注册中心订阅url
2.2.5 基于2.2.1的exporter构建心的Exporter并返回

RegistryProtocol.java
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //export invoker 
//1.构建Export,并启动NettyServer
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

        URL registryUrl = getRegistryUrl(originInvoker);  //获取注册中心地址

        //registry provider
        final Registry registry = getRegistry(originInvoker);  //2.获取Registry,
        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker); //
        //to judge to delay publish whether or not
        boolean register = registedProviderUrl.getParameter("register", true);

        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);

        if (register) {
//3.注册服务节点到zookeeper中(创建zk节点)
            register(registryUrl, registedProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

        // 4.订阅override数据
        // FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        //保证每次export都返回一个新的exporter实例
        return new Exporter<T>() {
            public Invoker<T> getInvoker() {
                return exporter.getInvoker();
            }

            public void unexport() {
                try {
                    exporter.unexport();
                } catch (Throwable t) {
                    logger.warn(t.getMessage(), t);
                }
                try {
                    registry.unregister(registedProviderUrl);
                } catch (Throwable t) {
                    logger.warn(t.getMessage(), t);
                }
                try {
                    overrideListeners.remove(overrideSubscribeUrl);
                    registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);
                } catch (Throwable t) {
                    logger.warn(t.getMessage(), t);
                }
            }
        };
    }

//构建Regisrty,这里会根据regisrtyurl中protocol=zookeeper  进入到ZookeeperRegisrtyFactory中创建Registry,启动zkclient等。
private Registry getRegistry(final Invoker<?> originInvoker) {
        URL registryUrl = getRegistryUrl(originInvoker);
        return registryFactory.getRegistry(registryUrl);
    }

//根据protocol构建真正的registryUrl
    private URL getRegistryUrl(Invoker<?> originInvoker) {
        URL registryUrl = originInvoker.getUrl();
        if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
            String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY);
            registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY);
        }
        return registryUrl;
    }
2.2.1.构建Exporter
我们先看看doLocalExport都做了什么: 【交互图1中步骤12开始(也就是交互图2)】
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
 /**这里获取provider地址 :
*dubbo://10.0.28.54:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-*provider&bind.ip=10.0.28.54&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=8956&side=provider×tamp=1522035115024
*/
        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.url为 prividerUrl;   因此url.protocol = dubbo
                    final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
//因此这里的protocol.export(invoker) 调用的实例变成了 DubboProtocol
                    exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                    bounds.put(key, exporter);
                }
            }
        }
        return exporter;
    }
因此,doLocalExport 主要负责构建Exporter,下面看看是如何使用DubboProtocol构建的。
在跳转到 DubboProtocol 前。会依次经过 【 ProtocolListenerWrapper, 管理Filter链的 ProtocolFilterWrapper 】进行filter包装,最后进入DubboProtocol
DubboProtocol.java
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);
                //如果是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());
        }

//当前入参Invoker为经过ProtocolFilterWrapper包装了Filter链之后的Invoker;
//阅读该方法可知,主要做几件事:
1.构建Exporter
2.如果是Stub则设置dubbo.stub.event.methods
3.打开NettyServer
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
       //dubbo://10.0.28.54:20880/com.alibaba.dubbo.demo.DemoService?
  	//anyhost=true&application=demo-provider&bind.ip=10.0.28.54&bind.port=20880&dubbo=2.0.0&generic=false&
 	//interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=8956&side=provider×tamp=1522035115024 
URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url); //com.alibaba.dubbo.demo.DemoService:20880
        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);
            }
        }
//创建nettySever
        openServer(url);

        return exporter;
    }

//创建nettyServer端实例,缓存中存在则返回缓存实例,否则新建Server
//缓存serverMap以 host:ip 为key 因此可知,一个服务器ip:port 只会出现一个server
   private void openServer(URL url) {
        // find server.
        String key = url.getAddress(); // ip:port
        //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);
            }
        }
    }

    private ExchangeServer createServer(URL url) {
        //默认开启server关闭时发送readonly事件  channel.readonly.sent = ture
        url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
        //默认开启heartbeat=60000 一分钟
        url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
        String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); // server=netty  默认使用的是netty

        if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
            throw new RpcException("Unsupported server type: " + str + ", url: " + url);

        url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);  //设置编解码的方式  此处 codec=dubbo
        ExchangeServer server;
        try {
//此时url为:
//dubbo://10.0.28.54:20880/com.alibaba.dubbo.demo.DemoService?
//anyhost=true&application=demo-provider&bind.ip=10.0.28.54
//&bind.port=20880&channel.readonly.sent=true&codec=dubbo&dubbo=2.0.0
//&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
//&pid=8956&side=provider×tamp=1522035115024
            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;
    }
创建Server的时候使用了 Exchangers.bind()
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);
    }
这里会获取到HeaderExchanger,并交由HeaderExchanger处理 这里会进一步封装Handler 【 DecodeHandler( headerExchangeHandler) -> HeaderExchangeHandler( requestHandler)】
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }
Transporters.bind采用默认的NettyTransporter来构建 NettyServer:
NettyTransporter.java
 public Server bind(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyServer(url, listener);
    }
接着在构建NettyServer实例的过程中,再次封装Handler链【MultiMessageHandler( heartbeatHandler) -> HeartbeatHandler( allChannelHandler) -> AllChannelHandler( decodeHandler)】
并添加线程池【这里采用FixedThreadPool -> ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue < Runnable > workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
-> ThreadPoolExecutor( 200,200,0,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>(),new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url))】
请求执行默认超时时间timeout:1000ms, //见父类构造函数AbstractEndpoint
连接默认超时时间connect.timeout:3000ms
获取编解码方式(codec=dubbo)DubboCountCodec
accepts:0,
默认空闲时间idleTimeout:600000 //见父类构造函数AbstractServer
最后调用doOpen开启NettyServer
AbstractServer.java
public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
        super(url, handler);
        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(); //这里将调用子类启动NettyServer
            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);
        }
        DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
        executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
    }
NettyServer.java
protected void doOpen() throws Throwable {
        NettyHelper.setNettyLoggerFactory();
        ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));  //DEFAULT_IO_THREADS=5
        bootstrap = new ServerBootstrap(channelFactory);

        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
        channels = nettyHandler.getChannels();
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                ChannelPipeline pipeline = Channels.pipeline();
                pipeline.addLast("decoder", adapter.getDecoder());
                pipeline.addLast("encoder", adapter.getEncoder());
                pipeline.addLast("handler", nettyHandler);
                return pipeline;
            }
        });
        // bind
        channel = bootstrap.bind(getBindAddress());
    }
这里ChannelPipeline handler为 上层构建出的 MultiMessageHandler 经过 NettyServer包装后的handler: NettyHandler (NettyServer( MultiMessageHandler ))

到这,NettyServer创建完毕,原路返回至DubboProtocol.openServer... 返回构建好的DubboExporter....
dubboExporter返回后,RegistryProtocol又做了什么?请看【 交互图1中17步开始(也就是交互图3)
2.2.2.根据registryUrl获取Registry
我们先看看RegistryProtocol.getRegistry:
private Registry getRegistry(final Invoker<?> originInvoker) {
        URL registryUrl = getRegistryUrl(originInvoker);
        return registryFactory.getRegistry(registryUrl);
    }

    private URL getRegistryUrl(Invoker<?> originInvoker) {
        URL registryUrl = originInvoker.getUrl();
        if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
            String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY);
            registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY);
        }
        return registryUrl;
    }
getRegistryUrl会重新设置url的protocol,最后registryUrl为:
zookeeper://10.0.28.54:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0
&export=dubbo%3A%2F%2F10.0.28.54%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D10.0.28.54%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D8956%26side%3Dprovider%26timestamp%3D1522035115024
&pid=8956×tamp=1522035107435
因此 registryFactory.getRegistry(registryUrl) 将交由 ZookeeperRegistryFactory处理。

获取Registry过程交互图如下:
步骤1.3 AbstractRegistry.getRegistry 首先会从缓存Map中查看是否存在 【zookeeper://ip:port/com.alibaba.dubbo.registry.RegistryService】为key的registry值。有则直接返回缓存中的实例,没有则开始创建新的Registry并加入到缓存map中;
AbstractRegistry.java
public Registry getRegistry(URL url) {
        url = url.setPath(RegistryService.class.getName())
                .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
                .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
        String key = url.toServiceString();
        // 锁定注册中心获取过程,保证注册中心单一实例
        LOCK.lock();
        try {
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            // 释放锁
            LOCK.unlock();
        }
    }
步骤1.4创建Registry:这里根据url.protocol=zookeeper 知,创建的Registry为 ZookeeperRegistry,构造ZookeeperRegistry过程需要经过FailbackRegistry ,AbstractRegistry两个父类构造函数;
ZookeeperRegistryFactory.java
  public Registry createRegistry(URL url) {
        return new ZookeeperRegistry(url, zookeeperTransporter);
    }
AbstractRegistry.java
public AbstractRegistry(URL url) {
        setUrl(url);
        // 启动文件保存定时器
        syncSaveFile = url.getParameter(Constants.REGISTRY_FILESAVE_SYNC_KEY, false);
        String filename = url.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getParameter(Constants.APPLICATION_KEY) + "-" + url.getAddress() + ".cache");
        File file = null;
        if (ConfigUtils.isNotEmpty(filename)) {
            file = new File(filename);
            if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) {
                if (!file.getParentFile().mkdirs()) {
                    throw new IllegalArgumentException("Invalid registry store file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!");
                }
            }
        }
        this.file = file;
        loadProperties();
        notify(url.getBackupUrls());
    }

private void loadProperties() {
        if (file != null && file.exists()) {
            InputStream in = null;
            try {
                in = new FileInputStream(file);
                properties.load(in);
                if (logger.isInfoEnabled()) {
                    logger.info("Load registry store file " + file + ", data: " + properties);
                }
            } catch (Throwable e) {
                logger.warn("Failed to load registry store file " + file, e);
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        logger.warn(e.getMessage(), e);
                    }
                }
            }
        }
    }
首先父级构造函数 AbstractRegistry 会启动本地缓存文件定时器,并加载本地文件 ${user.home}/.dubbo/dubbo-registry-${application.name}-${address}.cache (如 C:\Users\0212149/.dubbo/dubbo-registry-demo-provider-10.0.28.54:2181.cache
接着调用notify 对backupUrl进行通知
FailbackRegistry.java
public FailbackRegistry(URL url) {
        super(url);
        int retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD); // DEFAULT_REGISTRY_RETRY_PERIOD=5000
        this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                // 检测并连接注册中心
                try {
                    retry();
                } catch (Throwable t) { // 防御性容错
                    logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
                }
            }
        }, retryPeriod, retryPeriod, TimeUnit.MILLISECONDS);
    }
父类FailbackRegistry 构造函数主要启动定时器对注册中心进行连接状态检测,断开则重启,检测频率:5s
ZookeeperRegistry.java
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
        super(url);
        if (url.isAnyHost()) {
            throw new IllegalStateException("registry address == null");
        }
        String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT); // DEFAULT_ROOT=dubbo
        if (!group.startsWith(Constants.PATH_SEPARATOR)) {
            group = Constants.PATH_SEPARATOR + group;
        }
        this.root = group;
        zkClient = zookeeperTransporter.connect(url);
        zkClient.addStateListener(new StateListener() {
            public void stateChanged(int state) {
                if (state == RECONNECTED) {
                    try {
                        recover();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        });
    }
ZookeeperRegistry 构造函数将会使用 ZookeeperTransporter$Adatpive 来获取 ZookeeperClient;并添加zk状态监听(主要是连接断开重连)
ZookeeperTransporter$Adaptive 使用默认的zkclient来处理,因此,connect操作最终交由 ZkclientZookeeperTransporter处理:
ZkclientZookeeperTransporter.java
public ZookeeperClient connect(URL url) {
        return new ZkclientZookeeperClient(url); //构造 一个 ZkclientZookeeperClient 实例
    }
步骤 1.5创建 ZookeeperClient,ZookeeperClient构造时会通过 构建 ZkClientWrapper 实例来异步(FutureTask)创建ZkClient实例并获取
ZkclientZookeeperClient.java
 public ZkclientZookeeperClient(URL url) {
        super(url);
        client = new ZkClientWrapper(url.getBackupAddress(), 30000);
        client.addListener(new IZkStateListener() {
            public void handleStateChanged(KeeperState state) throws Exception {
                ZkclientZookeeperClient.this.state = state;
                if (state == KeeperState.Disconnected) {
                    stateChanged(StateListener.DISCONNECTED);
                } else if (state == KeeperState.SyncConnected) {
                    stateChanged(StateListener.CONNECTED);
                }
            }

            public void handleNewSession() throws Exception {
                stateChanged(StateListener.RECONNECTED);
            }
        });
        client.start();
    }

这里创建的是 ZkclientZookeeperClient ZkclientZookeeperClient 构造函数将对client初始化(new ZkClientWrapper (), ZkClientWrapper 返回的是持有 ZkClient 的实例)
ZkClientWrapper.java
//这里构造函数内会创建  新建 ZkClient实例的 future任务
public ZkClientWrapper(final String serverAddr, long timeout) {
        this.timeout = timeout;
        listenableFutureTask = ListenableFutureTask.create(new Callable<ZkClient>() {
            @Override
            public ZkClient call() throws Exception {
                return new ZkClient(serverAddr, Integer.MAX_VALUE);
            }
        });
    }

// ZkclientZookeeperClient 构造函数调用 start(),真正执行future任务,构建ZkClient实例。
    public void start() {
        if (!started) {
            Thread connectThread = new Thread(listenableFutureTask);
            connectThread.setName("DubboZkclientConnector");
            connectThread.setDaemon(true);
            connectThread.start();
            try {
                client = listenableFutureTask.get(timeout, TimeUnit.MILLISECONDS);
            } catch (Throwable t) {
                logger.error("Timeout! zookeeper server can not be connected in : " + timeout + "ms!", t);
            }
            started = true;
        } else {
            logger.warn("Zkclient has already been started!");
        }
    }

到这里,zkClient 创建完毕。也就是 Registry的构建完毕
2.2.3.注册服务节点到zookeeper中(创建zk节点)

创建节点交互流程如下:
我们先看看源码片段 export 方法在获取到Registry之后接着执行 服务节点注册到zk操作;调用register方法,如下:
 public void register(URL registryUrl, URL registedProviderUrl) {
        Registry registry = registryFactory.getRegistry(registryUrl);
        registry.register(registedProviderUrl);
    }
有代码可知,provider将会被发送到zkclient并开始创建目录节点。下面具体分析执行流程

首先registry会点调用父类 AbstractRegistry对服务Url进行缓存, 父类FailbackRegistry 会检测错误注册列表,未注册列表中是否存在即将发布的服务url,如果存在,则删除;
接着调用ZookeeperRegistry发送注册请求(使用zkClient向zk注册节点),如果发生异常,则将url添加至注册失败列表中,定时重试。
AbstractRegistry.java
public void register(URL url) {
        if (url == null) {
            throw new IllegalArgumentException("register url == null");
        }
        if (logger.isInfoEnabled()) {
            logger.info("Register: " + url);
        }
        registered.add(url);
    }
FailbackRegistry.java
public void register(URL url) {
        if (destroyed.get()){
            return;
        }
        super.register(url); //调用父类方法将providerUrl缓存起来
        failedRegistered.remove(url); //错误注册列表中删除待发布的url
        failedUnregistered.remove(url);//未注册列表删除待发布url
        try {
            // 向服务器端发送注册请求
            doRegister(url);   
        } catch (Exception e) {
            Throwable t = e;

            // 如果开启了启动时检测,则直接抛出异常
            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                    && url.getParameter(Constants.CHECK_KEY, true)
                    && !Constants.CONSUMER_PROTOCOL.equals(url.getProtocol());
            boolean skipFailback = t instanceof SkipFailbackWrapperException;
            if (check || skipFailback) {
                if (skipFailback) {
                    t = t.getCause();
                }
                throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t);
            } else {
                logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);
            }

            // 将失败的注册请求记录到失败列表,定时重试
            failedRegistered.add(url);
        }
    }
ZookeeperRegistry.java
//在zk中创建providerUrl节点
//这里的入参url为:dubbo://10.0.28.54: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=1768&side=provider×tamp=1522227208103
protected void doRegister(URL url) {
        try {
//  zkClient.create(url,true) 这里true表示创建临时节点,会因为客户端会话的失效而被删除。调用 ZkClientZookeeperClient创建节点  【节点分类详情请看:zookeeper/zookeeper节点类型】
//toUrlPath(url) 将url转换成文件目录结构式的:
//	 /dubbo/com.alibaba.dubbo.demo.DemoService/providers/
//	dubbo%3A%2F%2F10.0.28.54%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D1768%26side%3Dprovider%26timestamp%3D1522227208103
            zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true)); 
        } catch (Throwable e) {
            throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }
ZkClientZookeeperClient.java
//path中包含文件分隔符,则说明为文件夹目录结构,尝试创建【如果不存在】(文件夹节点为持久化节点,会一直存在zk中,直到有删除操作来主动删除这个节点)
public void create(String path, boolean ephemeral) {
        int i = path.lastIndexOf('/');
        if (i > 0) {
            String parentPath = path.substring(0, i);
            if (!checkExists(parentPath)) {
                create(parentPath, false); //递归创建目录节点
            }
        }
        if (ephemeral) {
            createEphemeral(path); //最后创建叶子节点 (这里就是 encode(providerUrl))
        } else {
            createPersistent(path);
        }
    }
createEphemeral createPersistent 依次进入 ZkClientZookeeperClient -> ZkClientWrapper -> ZkClient 创建节点

zk创建节点流程结束。。。。
2.2.4 订阅url,监听zk节点变化

先回顾下2.2.4的代码:
RegistryProtocol.java export 方法有如下片段
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { 
// 4.订阅override数据
        // FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);  //首先会根据providerUrl 构建 overrideSubscribeUrl 
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); //调用Registry订阅
}



private URL getSubscribedOverrideUrl(URL registedProviderUrl) {
        return registedProviderUrl.setProtocol(Constants.PROVIDER_PROTOCOL)
                .addParameters(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY,
                        Constants.CHECK_KEY, String.valueOf(false));
    }
当前providerUrl为:
dubbo://10.0.28.54: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=13860&side=provider×tamp=1522467555446
overrideSubscribeUrl :
provider://10.0.28.54:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=13860&side=provider×tamp=1522467555446

注意,这里的 overrideSubscribeUrl protocol已经变成了 provider,且 category只设置了 configurations
接着构建 OverrideListener ,并调用ZookeeperRegistry 进行url订阅,目的是为了在目录下节点数据发生变化时通过zk的事件触发并调用 OverrideListener 重新根据新的参数生成exporter (OverrideListener notify方法)

订阅整个交互如下:
FailbackRegistry.java
public void subscribe(URL url, NotifyListener listener) {
        if (destroyed.get()){
            return;
        }
        super.subscribe(url, listener); //AbstractRegisrty
        removeFailedSubscribed(url, listener);
        try {
            // 向服务器端发送订阅请求
            doSubscribe(url, listener); //ZookeeperRegistry
        } catch (Exception e) {
            Throwable t = e;

            List<URL> urls = getCacheUrls(url);
            if (urls != null && urls.size() > 0) {
                notify(url, listener, urls);
                logger.error("Failed to subscribe " + url + ", Using cached list: " + urls + " from cache file: " + getUrl().getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/dubbo-registry-" + url.getHost() + ".cache") + ", cause: " + t.getMessage(), t);
            } else {
                // 如果开启了启动时检测,则直接抛出异常
                boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                        && url.getParameter(Constants.CHECK_KEY, true);
                boolean skipFailback = t instanceof SkipFailbackWrapperException;
                if (check || skipFailback) {
                    if (skipFailback) {
                        t = t.getCause();
                    }
                    throw new IllegalStateException("Failed to subscribe " + url + ", cause: " + t.getMessage(), t);
                } else {
                    logger.error("Failed to subscribe " + url + ", waiting for retry, cause: " + t.getMessage(), t);
                }
            }

            // 将失败的订阅请求记录到失败列表,定时重试
            addFailedSubscribed(url, listener);
        }
    }
AbstarctRegistry.java
public void subscribe(URL url, NotifyListener listener) {
        if (url == null) {
            throw new IllegalArgumentException("subscribe url == null");
        }
        if (listener == null) {
            throw new IllegalArgumentException("subscribe listener == null");
        }
        if (logger.isInfoEnabled()) {
            logger.info("Subscribe: " + url);
        }
        Set<NotifyListener> listeners = subscribed.get(url);
        if (listeners == null) {
            subscribed.putIfAbsent(url, new ConcurrentHashSet<NotifyListener>());
            listeners = subscribed.get(url);
        }
        listeners.add(listener);
    }

ZookeeperRegistry.subscribe 实际调用的是父类FailbackRegistry.subscribe(),
FailbackRegistry.subscribe()首先调用父类AbstarctRegistry将该url,listener 保存到已订阅列表 subscribed<url,Set<listener>> 中,
接着从订阅失败列表和未订阅列表中将该url对应的入参listener删除掉,最后调用ZookeeperRegistry.doSubscribe ()方法进行订阅;
ZookeeperRegistry.java
protected void doSubscribe(final URL url, final NotifyListener listener) {
        try {
            if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
                String root = toRootPath();
                ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                if (listeners == null) {
                    zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                    listeners = zkListeners.get(url);
                }
                ChildListener zkListener = listeners.get(listener);
                if (zkListener == null) {
                    listeners.putIfAbsent(listener, new ChildListener() {
                        public void childChanged(String parentPath, List<String> currentChilds) {
                            for (String child : currentChilds) {
                                child = URL.decode(child);
                                if (!anyServices.contains(child)) {
                                    anyServices.add(child);
                                    subscribe(url.setPath(child).addParameters(Constants.INTERFACE_KEY, child,
                                            Constants.CHECK_KEY, String.valueOf(false)), listener);
                                }
                            }
                        }
                    });
                    zkListener = listeners.get(listener);
                }
                zkClient.create(root, false);
                List<String> services = zkClient.addChildListener(root, zkListener);
                if (services != null && services.size() > 0) {
                    for (String service : services) {
                        service = URL.decode(service);
                        anyServices.add(service);
                        subscribe(url.setPath(service).addParameters(Constants.INTERFACE_KEY, service,
                                Constants.CHECK_KEY, String.valueOf(false)), listener);
                    }
                }
            } else {
                //执行else流程
                List<URL> urls = new ArrayList<URL>();

            //这里toCategoriesPath(url)会根据 url.category来构建需要注册到zk中的目录结构列表【格式:${root}/serviceName/category】,
            // 如category=configurations,则 则会构建成 /dubbo/com.alibaba.dubbo.demo.DemoService/configurators
            // 接着迭代构建的目录机构,更新zkListener<url,Map<NotifyListener, ChildListener>>,zkListener是以url为key,value为一个Map结构,该Map
            //结构key为 入参listener( overrideListener) ,value 为构建的zkChildListener;
                for (String path : toCategoriesPath(url)) {  
                    ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                    if (listeners == null) {
                        zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                        listeners = zkListeners.get(url);
                    }
                    ChildListener zkListener = listeners.get(listener);
                    if (zkListener == null) {
                        listeners.putIfAbsent(listener, new ChildListener() {
                            public void childChanged(String parentPath, List<String> currentChilds) {
                                 //这里的ChildListner  childChanged时间会在zk的path节点下数据发生变化时触发执行,最后执行的是Zookeeper.notify方法,notify方法会保存新的url到本地服务列表缓存文件中;
                                  // 同时会调用 overrideListener将新的url传入,overrideListener的notify方法会根据新的入参url与当前url比对,如果存在差异,则重新构建url的Exporter
                                ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds)); 
                            }
                        });
                        zkListener = listeners.get(listener);
                    }
                    zkClient.create(path, false); //创建目录
                    List<String> children = zkClient.addChildListener(path, zkListener); //这里添加zk上path目录的监听事件
                    if (children != null) {
                        urls.addAll(toUrlsWithEmpty(url, path, children));
                    }
                }
                notify(url, listener, urls);
            }
        } catch (Throwable e) {
            throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }
到这里,订阅逻辑完毕。

Exporter也构建完毕。。。。。

























猜你喜欢

转载自blog.csdn.net/hao495430759/article/details/79924470