dubbo服务暴露

ServiceBean#onApplicationEvent(ContextRefreshedEvent)

ServiceConfig#export()

ServiceConfig#doExport()
首先校验该service的配置是否为空,则加载dubbo:provider、dubbo:module、dubbo:application缺省配置,若还为空则加载dubbo.properties的配置。
配置覆盖策略

ServiceConfig#doExportUrls()

private void doExportUrls() {
		//加载注册中心url
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

首先看AbstractInterfaceConfig#loadRegistries(boolean)

protected List<URL> loadRegistries(boolean provider) {
		//检验registry是否为空
        checkRegistry();
        //遍历所有registry
        List<URL> registryList = new ArrayList<URL>();
        if (registries != null && !registries.isEmpty()) {
            for (RegistryConfig config : registries) {
                /*省略代码,参数校验*/
                if (address.length() > 0 && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                	//构造kv属性
                    Map<String, String> map = new HashMap<String, String>();
                    appendParameters(map, application);
                    appendParameters(map, config);
                    map.put("path", RegistryService.class.getName());
                    map.put("dubbo", Version.getProtocolVersion());
                    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
                    if (ConfigUtils.getPid() > 0) {
                        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                    }
                    if (!map.containsKey("protocol")) {
                        if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                            map.put("protocol", "remote");
                        } else {
                            map.put("protocol", "dubbo");
                        }
                    }
                    //生成url对象
                    List<URL> urls = UrlUtils.parseURLs(address, map);
                    for (URL url : urls) {
                        url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                        url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
                        if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                                || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }

生成的registry url如下图
dubbo服务暴露_第1张图片
接着回去看doExportUrls,循环调用ServiceConfig#doExportUrlsFor1Protocol(ProtocolConfig , List)

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        String name = protocolConfig.getName();
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }
        //把application、provider、protocol等配置读取到map中
        Map<String, String> map = new HashMap<String, String>();
        map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
        map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, provider, Constants.DEFAULT_KEY);
        appendParameters(map, protocolConfig);
        appendParameters(map, this);
        if (methods != null && !methods.isEmpty()) {
            for (MethodConfig method : methods) {
            /*省略代码,循环方法级别配置,一般不会配置方法的配置*/
            } // end of methods for
        }
        //是否泛化实现http://dubbo.apache.org/zh-cn/docs/user/demos/generic-service.html
        //普通service走else
        if (ProtocolUtils.isGeneric(generic)) {
            map.put(Constants.GENERIC_KEY, generic);
            map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
        } else {
            String revision = Version.getVersion(interfaceClass, version);
            if (revision != null && revision.length() > 0) {
                map.put("revision", revision);
            }
            //getWrapper通过javassist生成Wrapper类,保存到一个WRAPPER_MAP中
            //最后拿到所有方法的名称,拼接成method1,method2...,放到最初的那个map中
            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("NO method found in service interface " + interfaceClass.getName());
                map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
            } else {
                map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        //令牌验证,http://dubbo.apache.org/zh-cn/docs/user/demos/token-authorization.html
        if (!ConfigUtils.isEmpty(token)) {
            if (ConfigUtils.isDefault(token)) {
                map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString());
            } else {
                map.put(Constants.TOKEN_KEY, token);
            }
        }
        //是否本地方法,http://dubbo.apache.org/zh-cn/docs/user/demos/local-call.html
        if (Constants.LOCAL_PROTOCOL.equals(protocolConfig.getName())) {
            protocolConfig.setRegister(false);
            map.put("notify", "false");
        }
        //开始了,服务暴露
        String contextPath = protocolConfig.getContextpath();
        //http协议的配置?一般为空串
        if ((contextPath == null || contextPath.length() == 0) && provider != null) {
            contextPath = provider.getContextpath();
        }

        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        Integer port = this.findConfigedPorts(protocolConfig, name, map);//构造URL
        URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }

        String scope = url.getParameter(Constants.SCOPE_KEY);
        // scope在dubbo.apache.org dubbo:service没有了?以前老的网站好像写了
        // scope配置成none不暴露
        if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            // 不是配置remote就本地暴露(配置remote,表示只远程暴露)
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            // 不是配置local就远程暴露(配置local,表示只本地暴露)
            if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
                /*省略代码,logger*/
                if (registryURLs != null && !registryURLs.isEmpty()) {
                	//遍历所有注册中心
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
                        //监控中心,http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-monitor.html
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        /*省略代码,logger*/
                        // For providers, this is used to enable custom proxy to generate invoker
                        String proxy = url.getParameter(Constants.PROXY_KEY);
                        if (StringUtils.isNotEmpty(proxy)) {
                            registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
                        }
						//通过代理工厂获得invoker
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        //生成invoker的委托
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                        //远程暴露
                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
            }
        }
        this.urls.add(url);
    }

小结

  1. 读取各种配置,生成注册中心URL;
  2. 读取各种配置,生成服务的URL;
  3. 通过代理工厂将服务ref对象转化成invoker对象,并且生成委托;
  4. 远程暴露,将多个提供者保存到exporters。

接下来,分别讲一下本地暴露和远程暴露的细节。
这边涉及到dubbo的Adaptive,其实就是通过传入的参数获得一个具体实现。

本地暴露

ServiceConfig#exportLocal(URL)

private void exportLocal(URL url) {
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
        	//转换成local url
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
                    .setHost(LOCALHOST)
                    .setPort(0);
            //将class放到ThreadLocal
            ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
            //获得ProxyFactory生成invoker,先往下看
            //继续看protocol.export
            Exporter<?> exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            //最终会将生成的exporter加入到ServiceConfig的实例对象exporters中
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }

ProxyFactory$Adaptive#getInvoker(java.lang.Object , java.lang.Class , com.alibaba.dubbo.common.URL )

public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg2 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg2;
        //获得url中的协议
        String extName = url.getParameter("proxy", "javassist");
        if (extName == null)
            /*省略代码,throw异常*/
        //根据协议名称获得具体的ProxyFactory实现类,类似反射,ExtensionLoader为dubbo的扩展机制,这边不分析
        com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
        //获得invoker
        return extension.getInvoker(arg0, arg1, arg2);
    }

包装类,StubProxyFactoryWrapper#getInvoker(T proxy, Class type, URL url)

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
        return proxyFactory.getInvoker(proxy, type, url);
    }

实际调用类,JavassistProxyFactory#getInvoker(T proxy, Class type, URL url),默认协议Javassist

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO 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中的invokeMethod方法如下所示,可以看一下AbstractProxyInvoker的调用过程就明白了:

public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException
{ 
	org.apache.dubbo.demo.provider.DemoServiceImpl w; 
	try{ 
		w = ((org.apache.dubbo.demo.provider.DemoServiceImpl)$1); 
	}catch(Throwable e){ 
		throw new IllegalArgumentException(e); 
	} 
	try{ 
		if( "sayHello".equals( $2 )  &&  $3.length == 1 ) {
			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 org.apache.dubbo.demo.provider.DemoServiceImpl."); 
}

回来看protocol.export(proxyFactory.getInvoker(ref, (Class) interfaceClass, local)),和ProxyFactory一样动态生成了Protocol$Adaptive,Protocol$Adaptive#export(com.alibaba.dubbo.rpc.Invoker arg0)方法代码如下:

public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
        /*省略代码,参数null判断,throw异常*/
        com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            /*省略代码,throw异常*/
        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);
    }

上述代码中,Protocol为包装类,如下图所示:
dubbo服务暴露_第2张图片

调用了ProtocolFilterWrapper#export(Invoker invoker)

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
		//判断是不是registry协议
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        //本地暴露走这
        return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    }

ProtocolFilterWrapper#buildInvokerChain(final Invoker invoker, String key, String group),生成责任链

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        //根据URL的属性获得相应Activate的过滤器
        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;
    }

回到ProtocolFilterWrapper#export(Invoker invoker),protocol.export调用了QosProtocolWrapper#export(Invoker),2.5.8 新版本增加了 QOS 模块,本地服务不涉及。

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
		//判断是不是registry协议
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            startQosServer(invoker.getUrl());
            return protocol.export(invoker);
        }
        //本地暴露走这
        return protocol.export(invoker);
    }

ProtocolListenerWrapper#export(Invoker),由于本地暴露protocol为InjvmProtocol。

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
		//判断是不是registry协议
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        //本地暴露走这,先往下看
        //然后构造ListenerExporterWrapper,也是把参数赋值
        return new ListenerExporterWrapper<T>(protocol.export(invoker),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                        .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
    }

InjvmProtocol#export(Invoker),终于到最后了!!!

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
		//这边的ServiceKey为“接口名称:版本号”,如果没有版本号就为“接口名称”
		//exporterMap是InjvmProtocol抽象父类的对象变量,protected final Map> exporterMap
		//构造方法,把参数赋值到对象变量,并且exporterMap.put(key, this),this为InjvmExporter
		//所以所有本地暴露服务都放在exporterMap中
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }

回到ProtocolListenerWrapper#export(Invoker),构造ListenerExporterWrapper,把参数赋值。默认ExporterListener是空的。

最终回到本地暴露小节的开始,生成的Exporter如下图:
dubbo服务暴露_第3张图片

远程暴露

远程暴露是服务暴露的重点,涉及的内容比较多。
下面这段代码在上面提到过,远程暴露生成Invoker和本地暴露是类似的,只是URL不同。

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        /*省略无关代码,具体代码在上面提到过*/
        
        if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            // 不是配置remote就本地暴露(配置remote,表示只远程暴露)
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            // 不是配置local就远程暴露(配置local,表示只本地暴露)
            if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
                /*省略代码,logger*/
                if (registryURLs != null && !registryURLs.isEmpty()) {
                	//遍历所有注册中心
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
                        //监控中心,http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-monitor.html
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        /*省略代码,logger*/
                        // For providers, this is used to enable custom proxy to generate invoker
                        String proxy = url.getParameter(Constants.PROXY_KEY);
                        if (StringUtils.isNotEmpty(proxy)) {
                            registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
                        }
						//通过代理工厂获得invoker
						//registryURL.addParameterAndEncoded会将dubboURL以export为key加入到registryURL
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        //生成invoker的委托,将invoker和ServiceConfig绑定
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                        //远程暴露
                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
            }
        }
        this.urls.add(url);
    }

远程暴露的核心类(这个流程会反复出现)为RegisterProtocol所以Protocol$Adaptive动态获得了RegisterProtocol,ProtocolFilterWrapper和本地暴露一致,只是协议不同,本地暴露为InjvmProtocol,所以直接看到RegistryProtocol#export(final Invoker)方法。

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //导出服务部分,先往下看
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
        
        /*省略代码,下面会有写*/
        
        //保证每次export都返回一个新的exporter实例
        return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);
    }

RegistryProtocol#doLocalExport(final Invoker originInvoker)

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
		//从invoker中获得服务的URL,默认是dubbo://开头的URL
        String key = getCacheKey(originInvoker);
        //从缓存中获得exporter,如果已经暴露就不再暴露
        ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
        //双重检查锁
        if (exporter == null) {
            synchronized (bounds) {
                exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
                if (exporter == null) {
                	//将originInvoker和服务的URL(默认dubbo://开头的URL)封装到一个委托中
                    final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
                    //生成Exporter流程与本地暴露相同
                    //由于默认dubbo协议,所以protocol包装类最终的protocol为DubboProtocol,只是最后会调用DubboProtocol#export(Invoker invoker)
                    exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                    //写缓存
                    bounds.put(key, exporter);
                }
            }
        }
        return exporter;
    }

DubboProtocol#export(Invoker invoker)

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();
        // 和本地暴露一样,远程暴露DubboProtocol中也有一个exporterMap,记录了暴露的服务
    	// key由服务组名,服务名,服务版本号以及端口组成
    	//没有设置group和版本号,key为pers.congzhou.service.DemoService:20880
    	//如全设置为demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
        String key = serviceKey(url);
        //构造DubboExporter
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        //加入缓存
        exporterMap.put(key, exporter);
		//本地存根,http://dubbo.apache.org/zh-cn/docs/user/demos/local-stub.html
        //跳过,消费者端为调度事件导出存根服务
        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*/
                }
            } else {
                stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
            }
        }
		//启动服务器
        openServer(url);
        //优化序列化
        optimizeSerialization(url);
        return exporter;
    }

启动服务器实例

DubboProtocol#openServer(URL url)

private void openServer(URL url) {
        // 获取地址(host:port),并将其作为服务器实例的 key,用于标识当前的服务器实例
        String key = url.getAddress();
        // 官方注释:client 也可以暴露一个只有server可以调用的服务。
        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
        if (isServer) {
        	//缓存,不存在就创建一个,默认只启动一个
            ExchangeServer server = serverMap.get(key);
            if (server == null) {
                serverMap.put(key, createServer(url));
            } else {
                // 服务器已存在,则根据URL中的配置重置服务器
                server.reset(url);
            }
        }
    }

DubboProtocol#createServer(URL url)

private ExchangeServer createServer(URL url) {
		//往URL加配置
        // 默认开启server关闭时发送readonly事件
        url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
        // 默认开启heartbeat
        url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
        //获得server参数,http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-protocol.html
        //dubbo协议缺省为netty,http协议缺省为servlet
        //这边我配置了netty4
        String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);

        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);
        ExchangeServer server;
        try {
        	//启动服务器
        	//Exchangers通过Adaptive机制获得Exchanger,默认为HeaderExchanger
            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;
    }

HeaderExchanger#bind(URL url, ExchangeHandler handler)方法的三个逻辑:

  1. HeaderExchangeHandler代理了DubboProtocol#requestHandler
  2. DecodeHandler代理了HeaderExchangeHandler
  3. bind,创建 NettyServer
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }

Transporters#bind(URL url, ChannelHandler… handlers)

public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
        /*省略代码,参数校验*/
        ChannelHandler handler;
        if (handlers.length == 1) {
            handler = handlers[0];
        } else {
            handler = new ChannelHandlerDispatcher(handlers);
        }
        //getTransporter()获得Adaptive
        return getTransporter().bind(url, handler);
    }

Transporter$Adaptive#bind(com.alibaba.dubbo.common.URL arg0, com.alibaba.dubbo.remoting.ChannelHandler arg1)

public com.alibaba.dubbo.remoting.Server bind(com.alibaba.dubbo.common.URL arg0, com.alibaba.dubbo.remoting.ChannelHandler arg1) throws com.alibaba.dubbo.remoting.RemotingException {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg0;
        String extName = url.getParameter("server", url.getParameter("transporter", "netty"));
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" + url.toString() + ") use keys([server, transporter])");
        //根据server参数获得具体Transporter实例,我使用的server参数为netty4
        com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.Transporter.class).getExtension(extName);
        return extension.bind(arg0, arg1);
    }

com.alibaba.dubbo.remoting.transport.netty4.NettyTransporter#bind(URL url, ChannelHandler listener)
netty启动的代码不写了,其中listener会被包装,当netty触发事件时会调用listener处理。

public Server bind(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyServer(url, listener);
    }

服务注册

回到远程暴露的核心类RegistryProtocol#export(final Invoker)
再贴一下代码:

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //导出服务部分
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
        //获得注册中心URL,zookeeper的URL为zookeeper://开头
        URL registryUrl = getRegistryUrl(originInvoker);
        // 获取 Registry,先往下看
        final Registry registry = getRegistry(originInvoker);
        //获得注册的URL,过滤了一些不需要的参数
        final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker);

        //判断是否延迟发布
        boolean register = registeredProviderUrl.getParameter("register", true);

        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl);

		//register过程,就刚刚回来的地方继续
        if (register) {
            register(registryUrl, registeredProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

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

RegistryProtocol#getRegistry(final Invoker originInvoker)

private Registry getRegistry(final Invoker<?> originInvoker) {
		//获得注册中心URL
        URL registryUrl = getRegistryUrl(originInvoker);
        //通过RegistryFactory$Adaptive获得具体实例,和其他Adaptive一样,就不贴代码了
        return registryFactory.getRegistry(registryUrl);
    }

zookeeper会获得ZookeeperRegistryFactory
AbstractRegistryFactory#getRegistry(URL url)

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 实例
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
            // 写缓存
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            LOCK.unlock();
        }
    }

ZookeeperRegistryFactory#createRegistry(URL url)

public Registry createRegistry(URL url) {
        return new ZookeeperRegistry(url, zookeeperTransporter);
    }
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
        super(url);
        if (url.isAnyHost()) {
            throw new IllegalStateException("registry address == null");
        }
        //获取组名,默认dubbo
        String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
        if (!group.startsWith(Constants.PATH_SEPARATOR)) {
        	//加上路径,/group
            group = Constants.PATH_SEPARATOR + group;
        }
        this.root = group;
        // 创建 Zookeeper 客户端,先往下看
        zkClient = zookeeperTransporter.connect(url);
        // 状态监听器
        zkClient.addStateListener(new StateListener() {
            @Override
            public void stateChanged(int state) {
                if (state == RECONNECTED) {
                    try {
                        recover();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        });
    }

ZookeeperTransporter$Adaptive,默认为 CuratorZookeeperTransporter,Apache Curator一个Zookeeper客户端。
CuratorZookeeperTransporter#connect(URL url)

public ZookeeperClient connect(URL url) {
        return new CuratorZookeeperClient(url);
    }
public CuratorZookeeperClient(URL url) {
        super(url);
        try {
        	// CuratorFramework 工厂,各种参数加进去
            CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                    .connectString(url.getBackupAddress())
                    .retryPolicy(new RetryNTimes(1, 1000))
                    .connectionTimeoutMs(5000);
            String authority = url.getAuthority();
            if (authority != null && authority.length() > 0) {
                builder = builder.authorization("digest", authority.getBytes());
            }
            // 构建 CuratorFramework 实例
            client = builder.build();
            // 添加监听器
            client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
                @Override
                public void stateChanged(CuratorFramework client, ConnectionState state) {
                    if (state == ConnectionState.LOST) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.DISCONNECTED);
                    } else if (state == ConnectionState.CONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.CONNECTED);
                    } else if (state == ConnectionState.RECONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.RECONNECTED);
                    }
                }
            });
            // 启动客户端
            client.start();
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

回到服务暴露的核心类,在贴一下代码就不需要往上看啦

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //导出服务部分
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
        //获得注册中心URL,zookeeper的URL为zookeeper://开头
        URL registryUrl = getRegistryUrl(originInvoker);
        // 获取 Registry,先往下看
        final Registry registry = getRegistry(originInvoker);
        
        //上面写到这边
        //获得注册的URL,过滤了一些不需要的参数
        final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker);

        //判断是否延迟发布
        boolean register = registeredProviderUrl.getParameter("register", true);

        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl);

		//register过程
        if (register) {
        	// 向注册中心注册服务
            register(registryUrl, registeredProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

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

RegistryProtocol#register(URL registryUrl, URL registedProviderUrl)

 public void register(URL registryUrl, URL registedProviderUrl) {
        Registry registry = registryFactory.getRegistry(registryUrl);
        registry.register(registedProviderUrl);
    }

ZookeeperRegistry的抽象父类FailbackRegistry#register(URL url)

public void register(URL url) {
		//加到一个hashset中
        super.register(url);
        failedRegistered.remove(url);
        failedUnregistered.remove(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#doRegister(URL url)

  1. toUrlPath 方法生成节点路径,路径格式/${group}/${serviceInterface}/providers/${url}
  2. 通过Zookeeper客户端创建节点
protected void doRegister(URL url) {
        try {
            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);
        }
    }

没有了!

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