dubbo源码解析之服务暴露/服务导出

Official website: http://dubbo.apache.org/zh-cn/docs/source_code_guide/export-service.html

暴露流程:

  • ClassPathXmlApplicationContext加载provider的xml文件
  • 解析<dubbo:service interface=“xxx.xxx” ref=“xxx”/>到ServiceConfig对象,并且进行服务暴露
  • 启动Netty服务端,向外提供tcp服务接口
  • 注册服务到注册中心
// 在这里开始 ServiceBean.java
// 不延迟导出:onApplicationEvent()
// 延迟导出:afterPropertiesSet()
public void onApplicationEvent(ContextRefreshedEvent event) {
    
    
    if (isDelay() && !isExported() && !isUnexported()) {
    
    
        ...
        export();
    }
}

// 不延迟导出:onApplicationEvent()
// 延迟导出:afterPropertiesSet()
public void afterPropertiesSet() throws Exception {
    
    
    ...
    if (!isDelay()) {
    
    
        export();
    }
}

// 是否延迟导出
private boolean isDelay() {
    
    
    // 针对单个服务配置延迟 eg. @Service(delay = 4000)
    // 默认delay值为0(启动会设置成null)
    Integer delay = getDelay();
    // 针对provider配置延迟 eg. <dubbo:provider filter="dubboFilter4Provider" delay="20"/>
    ProviderConfig provider = getProvider();
    if (delay == null && provider != null) {
    
    
        delay = provider.getDelay();
    }
    // true: (delay == null || delay == -1)
    // false: delay > 0
    return supportedApplicationListener && (delay == null || delay == -1);
}

// @Parameter的excluded为true表示不需要添加到URL的parameters中
@Parameter(excluded = true)
public boolean isExported() {
    
    
    return exported;
}

ServiceBean实现了ApplicationListener#onApplicationEvent(E),在容器初始化完成后执行。
ServiceBean也实现了InitializingBean#afterPropertiesSet(),可以实现延迟导出。

// 检查是否需要导出。不导出,直接返回
// 是否需要延迟导出。需要,则启动定时任务
// ServiceConfig.export()
public synchronized void export() {
    
    
    if (provider != null) {
    
    
        // 配置 @Service(export = false) 时,export会设置被设置成null
        // 配置 @Service(export = true) 时,export 才会为 true
        // ??? 但对以下的逻辑都没影响,是不是认为该参数没有作用的。
        if (export == null) {
    
    
            // 设置provider级的export是不会设置成null的
            // eg. <dubbo:provider export="false" />
            export = provider.getExport();
        }
        if (delay == null) {
    
    
            delay = provider.getDelay();
        }
    }
    // true: export == false
    // export == false时,该服务不可被远程调用
    if (export != null && !export) {
    
    
        return;
    }
    if (delay != null && delay > 0) {
    
     // delay > 0  休眠N毫秒再导出
        // 单线程定时调度线程池
        // private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
        delayExportExecutor.schedule(new Runnable() {
    
    
            public void run() {
    
    
                doExport();
            }
        }, delay, TimeUnit.MILLISECONDS);
    } else {
    
    
        doExport();
    }
}

// 检测 <dubbo:service> 标签的 interface 属性合法性
// 初始化application、module、registries、monitor、protocols等变量
// 检查以上对象是否为空
// ServiceConfig#doExport()
protected synchronized void doExport() {
    
    
    if (unexported) {
    
    
        throw new IllegalStateException("Already unexported!");
    }
    if (exported) {
    
    
        return;
    }
    exported = true;
    // 检测 <dubbo:service> 标签的 interface 属性合法性
    if (interfaceName == null || interfaceName.length() == 0) {
    
    
        throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
    }
    // 为ProviderConfig的设置property,从环境变量或配置文件中取dubbo.provider.<id>.<property> 和 dubbo.provider.<property>
    // 先从系统环境变量获取,获取不到,再从配置文件种获取
    // 配置文件路径可以通过启动参数:dubbo.properties.file或dubbo.properties配置
    checkDefault();
    // 初始化application、module、registries、monitor、protocols等变量
    if (provider != null) {
    
    
        if (application == null) {
    
    
            application = provider.getApplication();
        }
        if (module == null) {
    
    
            module = provider.getModule();
        }
        if (registries == null) {
    
    
            registries = provider.getRegistries();
        }
        if (monitor == null) {
    
    
            monitor = provider.getMonitor();
        }
        if (protocols == null) {
    
    
            protocols = provider.getProtocols();
        }
    }
    ...
    if (application != null) {
    
    
        if (registries == null) {
    
    
            registries = application.getRegistries();
        }
        if (monitor == null) {
    
    
            monitor = application.getMonitor();
        }
    }
    // TODO 这句话有什么作用
    if (ref instanceof GenericService) {
    
    
        interfaceClass = GenericService.class;
        if (StringUtils.isEmpty(generic)) {
    
    
            generic = Boolean.TRUE.toString();
        }
    } else {
    
    
        try {
    
    
            // 取得Class类类型对象
            interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                    .getContextClassLoader());
        } catch (ClassNotFoundException e) {
    
    
            throw new IllegalStateException(e.getMessage(), e);
        }
        checkInterfaceAndMethods(interfaceClass, methods);
        checkRef();
        generic = Boolean.FALSE.toString();
    }
    // 已废弃,请使用stub
    if (local != null) {
    
    
        // 此处的代码和下一个 if 分支的代码基本一致,这里省略
    }
    if (stub != null) {
    
    
        if ("true".equals(stub)) {
    
    
            stub = interfaceName + "Stub";
        }
        Class<?> stubClass;
        try {
    
    
            // 获取本地存根类
            stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
        } catch (ClassNotFoundException e) {
    
    
            throw new IllegalStateException(e.getMessage(), e);
        }
        // 检测本地存根类是否可赋值给接口类,若不可赋值则会抛出异常,提醒使用者本地存根类类型不合法
        if (!interfaceClass.isAssignableFrom(stubClass)) {
    
    
            throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
        }
    }
    // 为ApplicationConfig的设置property,从环境变量或配置文件中取dubbo.application.<id>.<property>和dubbo.application.<property>
    // 另外还设置dubbo.service.shutdown.wait和dubbo.service.shutdown.wait.seconds参数
    checkApplication();
    // 如果xml文件中未配置<dubbo:registry address="xxx"/>则从环境变量或配置文件中取dubbo.registry.address
    checkRegistry();
    // 如果xml文件未配置<dubbo:protocol name="dubbo" port="xxx"/>则从取<dubbo:provider protocol="xxx" />
    checkProtocol();
    // 为ServiceConfig的设置property,从环境变量或配置文件中取dubbo.service.<id>.<property> 和 dubbo.service.<property>
    appendProperties(this);
    checkStubAndMock(interfaceClass);
    if (path == null || path.length() == 0) {
    
    
        path = interfaceName;
    }
    // 导出链接URL
    doExportUrls();
    ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
    ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}

初始化ApplicationConfig、ProtocolConfig、ServiceConfig等对象,为导出做一些提前的准备工作。

// 导出链接URL
// ServiceConfig#doExportUrls()
private void doExportUrls() {
    
    
    // 加载注册中心链接
    List<URL> registryURLs = loadRegistries(true);
    // 遍历protocols,并在每个协议下导出服务
    for (ProtocolConfig protocolConfig : protocols) {
    
    
        // 暴露dubbo服务:<dubbo:protocol name="dubbo" port="20880" id="dubbo" />
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

// 检查是否配置了注册中心 eg. <dubbo:registry address="multicast://224.5.6.7:1234"/>
// 封装URL对象
// 返回注册中心列表
// AbstractInterfaceConfig#loadRegistries(boolean)
protected List<URL> loadRegistries(boolean provider) {
    
    
    // 如果xml文件中未配置<dubbo:registry address="xxx"/>则从环境变量或配置文件中取dubbo.registry.address
    checkRegistry();
    List<URL> registryList = new ArrayList<URL>();
    if (registries != null && registries.size() > 0) {
    
    
        for (RegistryConfig config : registries) {
    
    
            String address = config.getAddress();
            // 注册中心地址为空,则设置为0.0.0.0
            if (address == null || address.length() == 0) {
    
    
                address = Constants.ANYHOST_VALUE;
            }
            // 系统属性中获取注册中心地址
            String sysaddress = System.getProperty("dubbo.registry.address");
            if (sysaddress != null && sysaddress.length() > 0) {
    
    
                // 系统环境变量参数dubbo.registry.address会覆盖xml配置文件的注册中心地址
                address = sysaddress;
            }
            if (address != null && address.length() > 0
                    && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
    
    
                // 把ApplicationConfig、RegistryConfig、path、dubbo、timestamp、pid、protocol等放进map对象中
                Map<String, String> map = new HashMap<String, String>();
                appendParameters(map, application);
                appendParameters(map, config);
                map.put("path", RegistryService.class.getName());
                map.put("dubbo", Version.getVersion());
                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) {
    
    
                    // 添加"registry"="zookeeper"到URL.parameters
                    url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                    // 设置url.protocol="registry"
                    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;
}

初始化注册中心信息,并且存放在URL的对象中,以便后期做导出准备。

// 检查配置<dubbo:protocol name="dubbo" port="20886" />为空,默认协议为dubbo和端口20880
// 封装map集合参数,然后封装的URL对象中
// 导出服务到本地/远程
// ServiceConfig#doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs)
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    
    
    String name = protocolConfig.getName();
    if (name == null || name.length() == 0) {
    
    
        // 默认协议名为dubbo
        name = "dubbo";
    }

    Map<String, String> map = new HashMap<String, String>();
    // "side" -> "provider"
    map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
    // "dubbo" -> "2.0.2"
    map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
    // "timestamp" -> "1568339911006"
    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
    // "pid" -> "13072"
    if (ConfigUtils.getPid() > 0) {
    
    
        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
    }
    // "application" -> "demo-provider"
    // ...
    appendParameters(map, application);
    appendParameters(map, module);
    appendParameters(map, provider, Constants.DEFAULT_KEY);
    appendParameters(map, protocolConfig);
    // "interface" -> "com.alibaba.dubbo.demo.DemoService"
    // "bean.name" -> "com.alibaba.dubbo.demo.DemoService"
    appendParameters(map, this);
    if (methods != null && methods.size() > 0) {
    
    
        // MethodConfig保存了<dubbo:method>的信息
        for (MethodConfig method : methods) {
    
    
            // 添加 MethodConfig 对象的字段信息到 map 中,键 = 方法名.属性名。
            // eg. <dubbo:method name="sayHello" retries="2"> => {"sayHello.retries": 2}
            appendParameters(map, method, method.getName());
            String retryKey = method.getName() + ".retry";
            if (map.containsKey(retryKey)) {
    
    
                String retryValue = map.remove(retryKey);
                if ("false".equals(retryValue)) {
    
    
                    map.put(method.getName() + ".retries", "0");
                }
            }
            // 解析<dubbo:argument index="1"/>
            // 参考:http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-argument.html
            List<ArgumentConfig> arguments = method.getArguments();
            if (arguments != null && arguments.size() > 0) {
    
    
                for (ArgumentConfig argument : arguments) {
    
    
                    // convert argument type
                    ...
                }
            }
        } // end of methods for
    }

    if (ProtocolUtils.isGeneric(generic)) {
    
    
        map.put("generic", generic);
        map.put("methods", Constants.ANY_VALUE);
    } else {
    
    
        // 获取接口版本<dubbo:service interface="xxxService" version="1.0.0">
        String revision = Version.getVersion(interfaceClass, version);
        if (revision != null && revision.length() > 0) {
    
    
            map.put("revision", revision);
        }
        // 通过Wrapper#makeWrapper(Class<?>)生成一个Wrapper的实现类Wrapper0,通过Wrapper0取到所有方法名
        // TODO 为什么要大费周章,而不是用Method[] methods = c.getMethods();直接获取呢
        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
        if (methods.length == 0) {
    
    
            logger.warn("NO method found in service interface " + interfaceClass.getName());
            map.put("methods", Constants.ANY_VALUE);
        } else {
    
    
            // 添加所有的方法名到map集合。方法名以逗号分隔
            map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
        }
    }
    // 添加token到map集合
    if (!ConfigUtils.isEmpty(token)) {
    
    
        if (ConfigUtils.isDefault(token)) {
    
    
            map.put("token", UUID.randomUUID().toString());
        } else {
    
    
            map.put("token", token);
        }
    }
    // <dubbo:protocol name="injvm"/> 为本地测试
    if ("injvm".equals(protocolConfig.getName())) {
    
    
        protocolConfig.setRegister(false);
        // 不需要监听通知
        map.put("notify", "false");
    }

    String contextPath = protocolConfig.getContextpath();
    if ((contextPath == null || contextPath.length() == 0) && provider != null) {
    
    
        contextPath = provider.getContextpath();
    }
    // 获取host和port
    // 先从环境变量中获取DUBBO_DUBBO_IP_TO_BIND或DUBBO_IP_TO_BIND
    // 从<dubbo:protocol />中取host参数
    // 从<dubbo:provider />中取host参数
    // 以上都获取失败了,则取本机的ip地址(官方推荐不要配置该参数)
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    // 先从环境变量中获取DUBBO_DUBBO_PORT_TO_BIND或DUBBO_PORT_TO_BIND
    // 从<dubbo:protocol />中取host参数
    // 从<dubbo:provider />中取host参数
    // 以上都获取失败了,则取默认的dubbo服务暴露端口20880(在DubboProtocol.DEFAULT_PORT)
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    // 承载dubbo暴露接口配置信息
    URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

    // TODO 不知道干嘛的
    if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
            .hasExtension(url.getProtocol())) {
    
    
        url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
    }
    // 获取provider的scope配置 eg. <dubbo:provider scope="local" />
    String scope = url.getParameter(Constants.SCOPE_KEY);
    // scope == null || scope != "none"
    if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
    
    
        // (scope == null || scope != "remote") => 导出本地
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
    
    
            exportLocal(url);
        }
        // (scope == null || scope != "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.size() > 0) {
    
    
                // 遍历注册中心URL
                for (URL registryURL : registryURLs) {
    
    
                    url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                    // 加载Service监控对象MonitorConfig
                    // 另有章节详细讲解监控的实现
                    URL monitorUrl = loadMonitor(registryURL);
                    if (monitorUrl != null) {
    
    
                        // 添加"monitor":"监控地址"到url.parameters
                        url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                    }
                    ...
                    // For providers, this is used to enable custom proxy to generate invoker
                    String proxy = url.getParameter(Constants.PROXY_KEY);
                    if (StringUtils.isNotEmpty(proxy)) {
    
    
                        // 为注册中心的url.parameters添加参数proxy
                        registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
                    }
                    // 为服务提供类(ref)生成Invoker
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                    // 封装invoker和ServiceConfig到DelegateProviderMetaDataInvoker
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                    // 导出服务
                    // 注册中心暴露服务过程:ProtocolFilterWrapper -> ProtocolListenerWrapper -> RegistryProtocol
                    // dubbo暴露服务过程:ProtocolFilterWrapper -> ProtocolListenerWrapper -> DubboProtocol
                    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);
}

初始化URL(用于承载Dubbo服务暴露的),并封装各种参数到url.parameters属性中。下面分析一下DubboProtocol和RegistryProtocol的导出服务的过程。

// 导出DelegateProviderMetaDataInvoker
// Exporter<?> exporter = protocol.export(wrapperInvoker);
// DubboProtocol.export(wrapperInvoker);
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    
    
    URL url = invoker.getUrl();

    // 获取服务标识。由服务组名,服务名,服务版本号以及端口组成。
    // eg. demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
    String key = serviceKey(url);
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    // put到缓存
    // Map<String, Exporter<?>> exporterMap
    exporterMap.put(key, exporter);

    // 从url获取dubbo.stub.event参数
    Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
    // 从url获取is_callback_service参数
    Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
    
    
        // TODO 暂不深入
        String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
    
    
            ...
        } else {
    
    
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }
    // 启动Netty服务器端
    openServer(url);
    return exporter;
}

// DubboProtocol#openServer(URL)
private void openServer(URL url) {
    
    
    // find server.
    // eg. 10.0.75.1:20880
    String key = url.getAddress();
    //client can export a service which's only for server to invoke
    boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
    if (isServer) {
    
    
        ExchangeServer server = serverMap.get(key);
        if (server == null) {
    
    
            // 该dubbo协议还没有Netty服务端
            // 创建Netty服务端
            serverMap.put(key, createServer(url));
        } else {
    
    
            // server supports reset, use together with override
            server.reset(url);
        }
    }
}

// DubboProtocol#createServer(URL url)
private ExchangeServer createServer(URL url) {
    
    
    // send readonly event when server closes, it's enabled by default
    // "channel.readonly.sent" -> "true"
    url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
    // enable heartbeat by default
    // "heartbeat" -> "60000"
    url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
    // 获取服务端类型,默认netty
    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);

    // "codec" -> "dubbo"
    url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
    ExchangeServer server;
    try {
    
    
        // 
        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;
}

// Exchangers#bind(URL, ExchangeHandler)
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    
    
    ...
    // 上面设置了"codec" -> "dubbo",因此不会执行下面方法
    // CODEC_KEY
    url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
    // getExchanger(url)默认获得HeaderExchanger实例
    return getExchanger(url).bind(url, handler);
}

// HeaderExchanger#bind(URL, ExchangeHandler)
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    
    
    // 通过Transporters#bind(URL, ChannelHandler...)获取一个Server实例
    // 通过Server实例创建一个HeaderExchangeServer实例
    // HeaderExchangeServer使用的是装饰器模式,对NettyServer的增强,增加心跳机制
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

// Transporters#bind(URL, ChannelHandler...)
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
    
    
    ...
    ChannelHandler handler;
    if (handlers.length == 1) {
    
    
        handler = handlers[0];
    } else {
    
    
        // ChannelHandlerDispatcher包含Collection<ChannelHandler> channelHandlers,是多个ChannelHandler的封装
        handler = new ChannelHandlerDispatcher(handlers);
    }
    // getTransporter()默认获得NettyTransporter实例
    return getTransporter().bind(url, handler);
}

// NettyTransporter#bind(URL, ChannelHandler)
// NettyTransporter负责Netty服务端的绑定、Netty客户端的连接
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
    
    
    return new NettyServer(url, listener);
}

使用DubboProtocol对暴露dubbo服务。初始化Netty服务端,开启Netty服务,对外提供Netty服务。关于Netty如何解码编码暂不做详细分析。
接下来,分析一下RegistryProtocol是如何把服务注册到注册中心的。

// 导出DelegateProviderMetaDataInvoker
// Exporter<?> exporter = protocol.export(wrapperInvoker);
// RegistryProtocol.export(wrapperInvoker)
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    
    
    ...
    boolean register = registeredProviderUrl.getParameter("register", true);
    if (register) {
    
    
        // 注册服务
        register(registryUrl, registedProviderUrl);
        ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
    }
    ...
}
public void register(URL registryUrl, URL registedProviderUrl) {
    
    
    // 创建注册中心
    // ZookeeperRegistryFactory.createRegistry(URL url)
    Registry registry = registryFactory.getRegistry(registryUrl);
    // 注册服务
    // FailbackRegistry.register(URL url)
    registry.register(registedProviderUrl);
}

// 创建注册中心
// ZookeeperRegistryFactory.createRegistry(URL url)
public Registry createRegistry(URL url) {
    
    
    return new ZookeeperRegistry(url, zookeeperTransporter);
}
// ZookeeperRegistry的构造方法
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
        group = Constants.PATH_SEPARATOR + group;
    }
    this.root = group;
    // 创建 Zookeeper 客户端,默认为 CuratorZookeeperTransporter
    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);
                }
            }
        }
    });
}

// 注册服务
// FailbackRegistry.register(URL url)
public void register(URL url) {
    
    
    if (destroyed.get()){
    
    
        return;
    }
    super.register(url);
    failedRegistered.remove(url);
    failedUnregistered.remove(url);
    try {
    
    
        // 调用注册中心注册
        // 以Zookeeper为例分析
        // ZookeeperRegistry.doRegister(URL url)
        doRegister(url);
    } catch (Exception e) {
    
    
        ...
    }
}

// Zookeeper注册中心注册
// ZookeeperRegistry.doRegister(URL url)
protected void doRegister(URL url) {
    
    
    try {
    
    
        zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
    } catch (Throwable e) {
    
    
        ...
    }
}

Zookeeper通过创建节点保存服务提供者信息,暴露服务。

猜你喜欢

转载自blog.csdn.net/fomeiherz/article/details/100545601