Dubbo源码解析 - 服务导出(三)

ServiceConfig#doExportUrlsFor1Protocol

	if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            // 加载 ConfiguratorFactory,并生成 Configurator 实例,然后通过实例配置 url
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }
		// 如果scope=none,则什么都不做
        String scope = url.getParameter(SCOPE_KEY);
        // don't export when none is configured
        if (!SCOPE_NONE.equalsIgnoreCase(scope)) {

            // export to local if the config is not remote (export to remote only when config is remote)
            // scope != remote,导出到本地
            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            // export to remote if the config is not local (export to local only when config is local)
            // scope != local,导出到远程
            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
                if (!isOnlyInJvm() && logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                }
                if (CollectionUtils.isNotEmpty(registryURLs)) {
                    for (URL registryURL : registryURLs) {
                        //if protocol is only injvm ,not register
                        if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
                            continue;
                        }
                        url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
                        // 加载监视器链接
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            // 将监视器链接作为参数添加到 url 中
                            url = url.addParameterAndEncoded(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(PROXY_KEY);
                        if (StringUtils.isNotEmpty(proxy)) {
                            registryURL = registryURL.addParameter(PROXY_KEY, proxy);
                        }
						// 为服务提供者生成invoker
                        Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
                        // DelegateProviderMetaDataInvoker 用于持有 Invoker 和 ServiceConfig
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
						// 导出服务,并生成 Exporter
                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                // 不存在注册中心,仅导出服务
                } else {
                    Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
                /**
                 * @since 2.7.0
                 * ServiceData Store
                 */
                MetadataReportService metadataReportService = null;
                if ((metadataReportService = getMetadataReportService()) != null) {
                    metadataReportService.publishProvider(url);
                }
            }
        }
        this.urls.add(url);
    }

ServiceConfig#exportLocal - 导出服务到本地

Dubbo源码解析 - 服务导出(三)_第1张图片

在这里插入图片描述

`

RegistryProtocol#export - 导出服务到远程

Dubbo源码解析 - 服务导出(三)_第2张图片

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {

    /* originInvoker :DelegateProviderMetaDataInvoker类型 */
    /* 获取注册中心URL */
    URL registryUrl = getRegistryUrl(originInvoker);
    
    // url to export locally
    /* 获取服务提供者URL */
    URL providerUrl = getProviderUrl(originInvoker);

    // Subscribe the override data 
    /* 获取订阅URL */
    final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
    /* 创建监听器 */
    final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
    providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
    
    //export invoker
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);

	/* 获取注册中心实现类,即ZooKeeperRegistry */
    final Registry registry = getRegistry(originInvoker);
    
     // 获取已注册的服务提供者 URL
    final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
    
    /* 向服务提供者与消费者注册表中注册服务提供者 */
    ProviderInvokerWrapper<T> providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
            registryUrl, registeredProviderUrl);
            
  	/* 根据 register 的值决定是否注册服务 */
    boolean register = registeredProviderUrl.getParameter("register", true);
    if (register) {
    	/* 向注册中心注册服务 */
        register(registryUrl, registeredProviderUrl);
        providerInvokerWrapper.setReg(true);
    }

    // Deprecated! Subscribe to override rules in 2.6.x or before.
    /* 向注册中心进行订阅 override 数据 */
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);

    exporter.setRegisterUrl(registeredProviderUrl);
    exporter.setSubscribeUrl(overrideSubscribeUrl);
    // Ensure that a new exporter instance is returned every time export
    return new DestroyableExporter<>(exporter);
}

ExporterChageableWrapper#doLocalExport

在这里插入图片描述

  • bounds:ConcurrentMap>

`

DubboProtocol#export

@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    URL url = invoker.getUrl();
    String key = serviceKey(url);
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    exporterMap.put(key, exporter);

	/* 本地存根相关代码 */
    //export an stub service for dispatching event
    /* STUB_EVENT_KEY = "dubbo.stub.event" */
    /* DEFAULT_STUB_EVENT = false */
    Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
    
    /* IS_CALLBACK_SERVICE = "is_callback_service" */
    Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);

    if (isStubSupportEvent && !isCallbackservice) {
    	/* STUB_EVENT_METHODS_KEY = "dubbo.stub.event.methods" */
        String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
            if (logger.isWarnEnabled()) {
                logger.warn("..."));
            }
        } else {
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }

	/* 创建NettyServer,如果没有创建的话 */
    openServer(url);
    optimizeSerialization(url);

    return exporter;
}

`

DubboProtocol#openServer

Dubbo源码解析 - 服务导出(三)_第3张图片

  • key:192.168.0.106:20880。(我本地是192.168.0.106,加上设置的Dubbo协议的暴露接口是20880),用于标识当前的服务器实例。
  • IS_SERVER_KEY : “isserver”。
  • server.reset(url) : 根据url中的配置重置服务器。

`

DubboProtocol#createServer
private ExchangeServer createServer(URL url) {
    url = URLBuilder.from(url)
            // send readonly event when server closes, it's enabled by default
            .addParameterIfAbsent("channel.readonly.sent", Boolean.TRUE.toString())
            // enable heartbeat by default
            .addParameterIfAbsent("heartbeat", String.valueOf(60 * 1000))
            .addParameter("codec", "dubbo")
            .build();
    String str = url.getParameter("server", "netty");

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

    ExchangeServer server = Exchangers.bind(url, requestHandler);
   
    str = url.getParameter("client");
    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;
}

`

ExchangeServer#bind

Dubbo源码解析 - 服务导出(三)_第4张图片

`

HeaderExchanger#bind
	@Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }

`

Transporters#bind

Dubbo源码解析 - 服务导出(三)_第5张图片

在这里插入图片描述

默认是NettyTransporter。

在这里插入图片描述

`

NettyServer#doOpen

Dubbo源码解析 - 服务导出(三)_第6张图片

Dubbo源码解析 - 服务导出(三)_第7张图片

这里采用org.apache.dubbo.remoting.transport.netty4的NettyServer。

@Override
protected void doOpen() throws Throwable {
    bootstrap = new ServerBootstrap();

    bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
    /* IO_THREADS_KEY:iothreads */
    /* 根据配置文件中的dubbo.provider.iothreads设置的值决定 */
    /* 如果配置文件没有设置,线程数默认取 (Runtime.getRuntime().availableProcessors() + 1) 和 32 的最小值 */
    workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
            new DefaultThreadFactory("NettyServerWorker", true));
	
	/* NettyServerHandler:ChannelInboundHandler与ChannelOutboundHandler的组合体 */
	/* 服务提供者与服务消费者进行远程交互的核心处理器 */
    final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
    /* channels:Map 也就是 */
    channels = nettyServerHandler.getChannels();

    bootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
            .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
            .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
            .childHandler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {
                  
                  	/* heartbeat.timeout */
                    int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
                    /* codec:Codec接口类型,由dubbo.provider.codec 或者 dubbo.protocol.codec 指定Codec实现类的全限定名 */
                    NettyCodecAdapter adapter = new NettyCodecAdapter(codec, url, NettyServer.this);
                    ch.pipeline()
                            .addLast("decoder", adapter.getDecoder())
                            .addLast("encoder", adapter.getEncoder())
                            .addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS))
                            .addLast("handler", nettyServerHandler);
                }
            });
 
    ChannelFuture channelFuture = bootstrap.bind(bindAddress);
    channelFuture.syncUninterruptibly();
    /* the boss channel that receive connections and dispatch these to worker channel. */
    channel = channelFuture.channel();

}

IdleStateHandler:
Dubbo源码解析 - 服务导出(三)_第8张图片

然后看下它的handlerAdded(…)方法,也就是当ChannelHandler添加到ChannelHandlerContext中触发的逻辑,如下:
Dubbo源码解析 - 服务导出(三)_第9张图片

initialize(…)方法,根据readerIdleTimeNanos、writerIdleTimeNanos、allIdleTimeNanos参数,如果有大于0,则延迟调度对应的ReaderIdleTimeoutTask、WriterIdleTimeoutTask、AllIdleTimeoutTask。实际上是触发ChannelInboundHandler#userEventTriggered(…)方法。

你可能感兴趣的:(Dubbo)