Dubbo源码解析之服务暴露过程-3服务暴露-远程暴露

本文深入解析Dubbo服务的远程暴露过程,包括registryURLs处理,生成代理Invoker,Invoker包装,以及export服务暴露的各个步骤。从遍历注册中心,到创建Netty服务器,再到注册服务到Zookeeper,全面剖析Dubbo服务暴露的细节。
摘要由CSDN通过智能技术生成

1.registryURLs处理

接着上节本地服务暴露过程,我们继续看下面的代码

        if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            // export to local if the config is not remote (export to remote only when config is remote)
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);	//本地暴露
            }
            // export to remote if the config is not local (export to local only when config is local)
            if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                }
                if (registryURLs != null && !registryURLs.isEmpty()) {
                	//遍历registryURLs进行远程服务暴露
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
                        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);
                        }

                        // 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);
                        }

                        //使用proxyFactory生成一个invoker   其实就是一个代理对象
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        //创建DelegateProvoderMetaInvoker对象进行包装
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                } else { //没有registryURLs
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

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

其中exportLocal就是本地暴露相关处理,下面的这部分内容就是远程暴露相关的处理,这里首先会遍历所有的注册中心,然后挨个儿进行处理,最终的url信息如下图:

 2.生成代理Invoker

Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));

这行代码会生成对应的代理对象,具体的生成方式上节详细说过,这里不再多说,断点一下这个Invoker,如下图:

3.对Invoker进行包装

DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

这行代码创建DelegateProvoderMetaInvoker对象对Invoker进行包装,主要是把原始的配置信息跟invoker绑在一块。DelegateProvoderMetaInvoker.java

public class DelegateProviderMetaDataInvoker<T> implements Invoker {
    protected final Invoker<T> invoker;
    private ServiceConfig metadata;

    public DelegateProviderMetaDataInvoker(Invoker<T> invoker,ServiceConfig metadata) {
        this.invoker = invoker;
        this.metadata = metadata;
    }
//省略代码
}

4.export服务暴露

与本地暴露一样,这里也会先走到ProtocolFilterWrapper的export方法,其源码如下:

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    	//invoker的url地址中的Protocol是否为registry
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    }

这里的registry非空的,所以会走到if条件里的内容,接下来会走到QosProtocolWrapper中的export方法,其源码如下:

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            startQosServer(invoker.getUrl());
            return protocol.export(invoker);
        }
        return protocol.export(invoker);
    }

这里有一个startQosServer操作,这里我们跟进去看一下

    private void startQosServer(URL url) {
        try {
        	//获取QOS_ENABLE(qos.enable)的值,未设置默认为true
            boolean qosEnable = url.getParameter(QOS_ENABLE,true);
            if (!qosEnable) {	//若为false  直接返回
                logger.info("qos won't be started because it is disabled. " +
                        "Please check dubbo.application.qos.enable is configured either in system property, " +
                        "dubbo.properties or XML/spring boot configuration.");
                return;
            }

            //将hasStarted的值从false修改为true  若修改失败直接返回
            if (!hasStarted.compareAndSet(false, true)) {
                return;
            }

            //获取端口  若未获取到,则返回DEFAULT_PORT(22222)
            int port = url.getParameter(QOS_PORT, DEFAULT_PORT);
            //获取url中qos.accept.foreign.ip的值,为空默认为false
            boolean acceptForeignIp = Boolean.parseBoolean(url.getParameter(ACCEPT_FOREIGN_IP,"false"));
            //获取一个Server实例
            Server server = com.alibaba.dubbo.qos.server.Server.getInstance();
            //设置server端口
            server.setPort(port);
            server.setAcceptForeignIp(acceptForeignIp);
            //启动server
            server.start();

        } catch (Throwable throwable) {
            logger.warn("Fail to start qos server: ", throwable);
        }
    }

这里获取了一个server的实例然后绑定了一个端口,这里是从url中获取qos.port的值,如果未获取到,则设置为22222,然后调用了server的start方法,我们看一下获取server的过程:

    private static final Server INSTANCE = new Server();

    public static final Server getInstance() {
        return INSTANCE;
    }

    private Server() {
        this.welcome = DubboLogo.dubbo;
    }

就是返回一个单例的Server对象,设置了welcome属性,如下:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值