Dubbo服务暴露源码分析

先放出总结:
(1)Dubbo服务暴露是将持有的服务实例通过代理转换成Invoker(一个真实的服务对象实例,可以是本地jvm实现、远程实现或是集群实现),然后把Invoker通过具体的协议(比如Dubbo)转换成Exporter。
(2)配置信息优先级覆盖策略:-D传递给JVM参数优先级最高,代码或者XML配置优先级次高,配置文件如dubbo.properties优先级最低。
(3)服务端和客户端配置覆盖策略:如果只有服务端指定配置,这些配置也会在客户端生效。如果客户端也配置了相应属性,那么服务端配置会被覆盖。
(4)服务暴露的入口在ServiceConfig#doExport,无论XML还是注解,都会转换成ServiceBean,ServiceBean是ServiceConfig的子类。
(5)Dubbo支持同一个服务暴露多个协议,如Dubbo协议和REST协议,每个协议注册元数据都会写入注册中心。

每一个标签都会被解析成一个BeanDefinition,然后注册成Bean。

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    
    

    static {
    
    
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    public void init() {
    
    
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
        registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
}

Dubbo会将每个需要暴露的服务解析为ServiceBean对象。
ServiceBean实现了ApplicationListener接口,对ContextRefreshedEvent进行监听。当Spring容器启动发布ContextRefreshedEvent,ServiceBean实例会触发onApplicationEvent方法,然后调用export方法。

public void onApplicationEvent(ContextRefreshedEvent event) {
    
    
    if (!isExported() && !isUnexported()) {
    
    
        if (logger.isInfoEnabled()) {
    
    
            logger.info("The service ready on spring started. service: " + getInterface());
        }
        export();
    }
}

ServiceBean是ServiceConfig的子类,ServiceBean#export会先去调用父类的export方法,然后发布ServiceBeanExportedEvent。

public void export() {
    
    
   super.export();
    // Publish ServiceBeanExportedEvent
    publishExportEvent();
}

ServiceConfig#export会调用checkAndUpdateSubConfigs方法检查参数配置,再执行doExport导出服务。

public synchronized void export() {
    
    
    checkAndUpdateSubConfigs();

    if (!shouldExport()) {
    
    
        return;
    }

    if (shouldDelay()) {
    
    
        DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
    } else {
    
    
        doExport();
    }
}

ServiceConfig#checkAndUpdateSubConfigs
(1)使用在全局配置上明确定义的默认配置。
(2)设置注解配置的优先级。
(3)检查ProviderConfig是否创建,如果没有,实例化一个。
(4)检查ProtocolConfig是否创建,如果没有,实例化一个。
(5)检查ApplicationConfig是否创建,如果没有,实例化一个。

public void checkAndUpdateSubConfigs() {
    
    
    // Use default configs defined explicitly on global configs
    completeCompoundConfigs();
    // Config Center should always being started first.
    startConfigCenter();
    checkDefault();
    checkProtocol();
    checkApplication();
    // if protocol is not injvm checkRegistry
    if (!isOnlyInJvm()) {
    
    
        checkRegistry();
    }
    this.refresh();
    checkMetadataReport();
}               

ServiceConfig没有的配置会使用ProviderConfig、ModuleConfig和ApplicationConfig的配置。

private void completeCompoundConfigs() {
    
    
    if (provider != null) {
    
    
        if (application == null) {
    
    
            setApplication(provider.getApplication());
        }
        if (module == null) {
    
    
            setModule(provider.getModule());
        }
        if (registries == null) {
    
    
            setRegistries(provider.getRegistries());
        }
        if (monitor == null) {
    
    
            setMonitor(provider.getMonitor());
        }
        if (protocols == null) {
    
    
            setProtocols(provider.getProtocols());
        }
        if (configCenter == null) {
    
    
            setConfigCenter(provider.getConfigCenter());
        }
    }
    if (module != null) {
    
    
        if (registries == null) {
    
    
            setRegistries(module.getRegistries());
        }
        if (monitor == null) {
    
    
            setMonitor(module.getMonitor());
        }
    }
    if (application != null) {
    
    
        if (registries == null) {
    
    
            setRegistries(application.getRegistries());
        }
        if (monitor == null) {
    
    
            setMonitor(application.getMonitor());
        }
    }
}

判断是否存在配置中心,如果存在配置中心,设置读取配置参数的优先级。

void startConfigCenter() {
    
    
    if (configCenter == null) {
    
    
        ConfigManager.getInstance().getConfigCenter().ifPresent(cc -> this.configCenter = cc);
    }

    if (this.configCenter != null) {
    
    
        // TODO there may have duplicate refresh
        this.configCenter.refresh();
        prepareEnvironment();
    }
    ConfigManager.getInstance().refreshAll();
}

AbstractConfig#refresh调用Environment#getConfiguration获取配置文件的优先级:JVM配置>操作系统配置>配置中心应用配置>配置中心全局配置>配置文件配置

如果Environment的configCenterFirst为true,配置文件优先级是:
JVM配置>操作系统配置>配置中心应用配置>配置中心全局配置>注解配置>配置文件配置

如果Environment的configCenterFirst为false,配置文件优先级是:
JVM配置>操作系统配置>注解配置>配置中心应用配置>配置中心全局配置>配置文件配置

循环遍历配置类(如ApplicationConfig)的所有方法,找出set方法,根据set后面的名称到各种配置方式中查找优先级最高的值,最后通过反射的方式给配置类的属性赋值。

public void refresh() {
    
    
    try {
    
    
        CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());
        Configuration config = new ConfigConfigurationAdapter(this);
        if (Environment.getInstance().isConfigCenterFirst()) {
    
    
            // The sequence would be: SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
            compositeConfiguration.addConfiguration(4, config);
        } else {
    
    
            // The sequence would be: SystemConfiguration -> AbstractConfig -> AppExternalConfiguration -> ExternalConfiguration -> PropertiesConfiguration
            compositeConfiguration.addConfiguration(2, config);
        }

        // loop methods, get override value and set the new value back to method
        Method[] methods = getClass().getMethods();
        for (Method method : methods) {
    
    
            if (MethodUtils.isSetter(method)) {
    
    
                try {
    
    
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
                    if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
    
    
                        method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
                    }
                } catch (NoSuchMethodException e) {
    
    
                    logger.info("Failed to override the property " + method.getName() + " in " +
                            this.getClass().getSimpleName() +
                            ", please make sure every property has getter/setter method provided.");
                }
            }
        }
    } catch (Exception e) {
    
    
        logger.error("Failed to override ", e);
    }
}

Environment#getConfiguration依次将JVM配置(SystemConfig)、系统配置(EnvironmentConfig)、应用配置(AppExternalConfig)、全局配置(ExternalConfig)和配置文件配置(PropertiesConfig)添加到List集合里。

public CompositeConfiguration getConfiguration(String prefix, String id) {
    
    
    CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
    // Config center has the highest priority
    compositeConfiguration.addConfiguration(this.getSystemConfig(prefix, id));
    compositeConfiguration.addConfiguration(this.getEnvironmentConfig(prefix, id));
    compositeConfiguration.addConfiguration(this.getAppExternalConfig(prefix, id));
    compositeConfiguration.addConfiguration(this.getExternalConfig(prefix, id));
    compositeConfiguration.addConfiguration(this.getPropertiesConfig(prefix, id));
    return compositeConfiguration;
}

CompositeConfiguration#getInternalProperty
根据key到各个配置中查找,如果不为空,就返回。

public Object getInternalProperty(String key) {
    
    
    Configuration firstMatchingConfiguration = null;
    for (Configuration config : configList) {
    
    
        try {
    
    
            if (config.containsKey(key)) {
    
    
                firstMatchingConfiguration = config;
                break;
            }
        } catch (Exception e) {
    
    
            logger.error("Error when trying to get value for key " + key + " from " + config + ", will continue to try the next one.");
        }
    }
    if (firstMatchingConfiguration != null) {
    
    
        return firstMatchingConfiguration.getProperty(key);
    } else {
    
    
        return null;
    }
}

判断是否符合条件的set方法:以set开头,方法名称不是set的public方法,且方法只能有一个基本类型的参数。

public class MethodUtils {
    
    
    public static boolean isSetter(Method method) {
    
    
        return method.getName().startsWith("set")
                && !"set".equals(method.getName())
                && Modifier.isPublic(method.getModifiers())
                && method.getParameterCount() == 1
                && ClassUtils.isPrimitive(method.getParameterTypes()[0]);
    }
}

判断Class是否为原始类型。

public static boolean isPrimitive(Class<?> type) {
    
    
    return type.isPrimitive()
            || type == String.class
            || type == Character.class
            || type == Boolean.class
            || type == Byte.class
            || type == Short.class
            || type == Integer.class
            || type == Long.class
            || type == Float.class
            || type == Double.class
            || type == Object.class;
}

ConfigManager#refreshAll最终调用AbstractConfig#refresh去更新application、monitor、module、protocol、registry、provider和consumer的配置。

public void refreshAll() {
    
    
    // refresh all configs here,
    getApplication().ifPresent(ApplicationConfig::refresh);
    getMonitor().ifPresent(MonitorConfig::refresh);
    getModule().ifPresent(ModuleConfig::refresh);

    getProtocols().values().forEach(ProtocolConfig::refresh);
    getRegistries().values().forEach(RegistryConfig::refresh);
    getProviders().values().forEach(ProviderConfig::refresh);
    getConsumers().values().forEach(ConsumerConfig::refresh);
}

ServiceConfig#doExport用于服务暴露

protected synchronized void doExport() {
    
    
        if (unexported) {
    
    
            throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
        }
        if (exported) {
    
    
            return;
        }
        exported = true;

        if (StringUtils.isEmpty(path)) {
    
    
            path = interfaceName;
        }
        doExportUrls();
    }

ServiceConfig#doExportUrls 将RegistryConfig转换成URL,再根据不同的protocol协议暴露服务。

注册的URL格式如下:
registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-provider-demo
&dubbo=2.0.2&pid=4400&qos.enable=false&registry=zookeeper&release=2.7.3&timestamp=1636259747478

loadRegistries:获取注册中心实例。
doExportUrlsFor1Protocol:循环不同协议暴露服务。

private void doExportUrls() {
    
    
    List<URL> registryURLs = loadRegistries(true);
    for (ProtocolConfig protocolConfig : protocols) {
    
    
        String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
        ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
        ApplicationModel.initProviderModel(pathKey, providerModel);
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

本地服务暴露机制

在本地暴露的URL:
injvm://127.0.0.1/gdut.DemoService?anyhost=true&application=dubbo-provider-demo
&bean.name=ServiceBean:gdut.DemoService:default&bind.ip=192.168.1.103&bind.port=20881&deprecated=false
&dubbo=2.0.2&dynamic=true&generic=false&interface=gdut.DemoService&methods=sayHello,sayHelloAsync&pid=21424
&qos.enable=false&register=true&release=2.7.3&revision=default&side=provider&timestamp=1636260108865&version=default

ServiceConfig#doExportUrlsFor1Protocol会调用exportLocal方法显示指定injvm协议进行暴露,将服务保存在内存中,同一个jvm的消费方可以直接调用,避免跨进程通信。

private void exportLocal(URL url) {
    
    
    URL local = URLBuilder.from(url)
            .setProtocol(LOCAL_PROTOCOL)
            .setHost(LOCALHOST_VALUE)
            .setPort(0)
            .build();
    Exporter<?> exporter = protocol.export(
            PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
    exporters.add(exporter);
    logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
}

以下是ServiceConfig#doExportUrlsFor1Protocol最关键的代码:
(1)通过动态代理生成一个Invoker。Dubbo有两种代理实现。
a.JavassistProxyFactory:创建wrapper子类,在子类实现invokeMethod方法,方法体内会为每个ref方法都做方法名和方法参数的校验,如果匹配直接调用即可。b.JdkProxyFactory:通过反射获取真实对象的方法。
ProxyFactory的SPI默认实现是JavassistProxyFactory。

调用Protocol#export生成一个Exporter对象。Protocol的默认SPI实现是DubboProtocol,这里的protocol是生成的Protocol$Adaptive代理类。这个代理类有三个包装类:ProtocolFilterWrapper,ProtocolListenerWraper和QosProtocolWrapper。最终会去调用RegistryProtocol#export(这里的URL协议是registry)。

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.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 = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

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

在这里插入图片描述
RegistryProtocol#export
调用doLocalExport暴露provider服务。调用register方法向注册中心注册服务。

registryUrl:
zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-provider-demo&dubbo=2.0.2&export=dubbo://192.168.1.103:20881/gdut.DemoService?anyhost=true&application=dubbo-provider-demo&bean.name=ServiceBean:gdut.DemoService:default&bind.ip=192.168.1.103&bind.port=20881&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=gdut.DemoService&methods=sayHello,sayHelloAsync&pid=20348&qos.enable=false&register=true&release=2.7.3&revision=default&side=provider&timestamp=1636295108119&version=default&pid=20348&qos.enable=false&release=2.7.3&timestamp=1636295108116

providerUrl:
dubbo://192.168.1.103:20881/gdut.DemoService?anyhost=true&application=dubbo-provider-demo&bean.name=ServiceBean:gdut.DemoService:default&bind.ip=192.168.1.103&bind.port=20881&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=gdut.DemoService&methods=sayHello,sayHelloAsync&pid=20348&qos.enable=false&register=true&release=2.7.3&revision=default&side=provider&timestamp=1636295108119&version=default

overrideSubscribeUrl :
provider://192.168.1.103:20881/gdut.DemoService?anyhost=true&application=dubbo-provider-demo&bean.name=ServiceBean:gdut.DemoService:default&bind.ip=192.168.1.103&bind.port=20881&category=configurators&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=gdut.DemoService&methods=sayHello,sayHelloAsync&pid=20348&qos.enable=false&register=true&release=2.7.3&revision=default&side=provider&timestamp=1636295108119&version=default

(1)doLocalExport:调用具体的协议如Dubbo进行服务暴露,创建NettyServer监听端口和保存服务实例。
(2)getRegistry:创建注册中心对象,与注册中心创建TCP连接。
(3)register:注册服务元数据到注册中心。
(4)subscribe:订阅configurators节点,监听服务动态属性变更事件。
(5)DestroyableExporter:服务销毁如关闭端口、销毁注册服务信息等。

@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    
    
    URL registryUrl = getRegistryUrl(originInvoker);
    // url to export locally
    URL providerUrl = getProviderUrl(originInvoker);

    // Subscribe the override data
    // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call
    //  the same service. Because the subscribed is cached key with the name of the service, it causes the
    //  subscription information to cover.
    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);

    // url to registry
    final Registry registry = getRegistry(originInvoker);
    final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
    ProviderInvokerWrapper<T> providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
            registryUrl, registeredProviderUrl);
    //to judge if we need to delay publish
    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.
    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);
}

RegistryProtocol#doLocalExport通过providerUrl获取一个Invoker,然后最终调用DubboProtocol#export(因为这里的URL是dubbo协议的)。调用真正的protocol前,也会先去调用包装类:ProtocolFilterWrapper,ProtocolListenerWraper和QosProtocolWrapper

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
    
    
    String key = getCacheKey(originInvoker);

    return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
    
    
        Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
        return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
    });
}

ProtocolListenerWrapper#export
DubboProtocl生成的Exporter经过ListenerExporterWrapper包装会添加监听器ExporterListener,

 public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    
    
    if (REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
    
    
        return protocol.export(invoker);
    }
    return new ListenerExporterWrapper<T>(protocol.export(invoker),
            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                    .getActivateExtension(invoker.getUrl(), EXPORTER_LISTENER_KEY)));
}

ProtocolFilterWrapper#export
触发buildInvokerChain进行拦截器链构造。

 public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    
    
    if (REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
    
    
        return protocol.export(invoker);
    }
    return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
}

DubboProtocol#export
创建一个NettyServer用于在客户端和服务端传输数据。

Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>();

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    
    
    URL url = invoker.getUrl();

    // export service.
    String key = serviceKey(url);
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    exporterMap.put(key, exporter);

    //export an stub service for dispatching event
    Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
    Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
    
    
        String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
    
    
            if (logger.isWarnEnabled()) {
    
    
                logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
                        "], has set stubproxy support event ,but no stub methods founded."));
            }

        } else {
    
    
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }

    openServer(url);
    optimizeSerialization(url);

    return exporter;
}

调用DubbotProtocol#createServer创建ExchangeServer。

private void openServer(URL url) {
    
    
    // find server.
    String key = url.getAddress();
    //client can export a service which's only for server to invoke
    boolean isServer = url.getParameter(IS_SERVER_KEY, true);
    if (isServer) {
    
    
        ExchangeServer server = serverMap.get(key);
        if (server == null) {
    
    
            synchronized (this) {
    
    
                server = serverMap.get(key);
                if (server == null) {
    
    
                    serverMap.put(key, createServer(url));
                }
            }
        } else {
    
    
            // server supports reset, use together with override
            server.reset(url);
        }
    }
}

DubboProtocol#createServer获取的url如下:
dubbo://192.168.1.103:20881/gdut.DemoService?anyhost=true&application=dubbo-provider-demo
&bean.name=ServiceBean:gdut.DemoService:default&bind.ip=192.168.1.103&bind.port=20881
&channel.readonly.sent=true&codec=dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&heartbeat=60000
&interface=gdut.DemoService&methods=sayHello,sayHelloAsync&pid=15800&qos.enable=false&register=true&release=2.7.3
&revision=default&side=provider&timestamp=1636275140059&version
判断url是否有server参数,表示创建server的类型,如果没有,默认值是netty。

private ExchangeServer createServer(URL url) {
    
    
    url = URLBuilder.from(url)
            // send readonly event when server closes, it's enabled by default
            .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
            // enable heartbeat by default
            .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
            .addParameter(CODEC_KEY, DubboCodec.NAME)
            .build();
    String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);

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

    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(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
如果没有指定Exchanger的类型,通过getExhanger方法获得一个默认HeaderExchanger。

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

public static Exchanger getExchanger(URL url) {
    
    
    String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);
    return getExchanger(type);
}

public static Exchanger getExchanger(String type) {
    
    
    return ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
}

HeaderExchanger#bind

public class HeaderExchanger implements Exchanger {
    
    

    public static final String NAME = "header";
    
    @Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    
    
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }
}

Transporters#bind
创建一个Transporter$Adaptive代理类,调用NettyTransporter#bind创建NettyServer。

public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
    
    
    if (url == null) {
    
    
        throw new IllegalArgumentException("url == null");
    }
    if (handlers == null || handlers.length == 0) {
    
    
        throw new IllegalArgumentException("handlers == null");
    }
    ChannelHandler handler;
    if (handlers.length == 1) {
    
    
        handler = handlers[0];
    } else {
    
    
        handler = new ChannelHandlerDispatcher(handlers);
    }
    return getTransporter().bind(url, handler);
}

 public static Transporter getTransporter() {
    
    
     return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
 }

调用父类AbstractServer构造函数。

public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
    
    
    // you can customize name and type of client thread pool by THREAD_NAME_KEY and THREADPOOL_KEY in CommonConstants.
    // the handler will be warped: MultiMessageHandler->HeartbeatHandler->handler
    super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}

获取开启NettyServer需要绑定的IP和端口。调用NettySever#doOpen创建一个NettyServer。

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(ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {
    
    
        bindIp = ANYHOST_VALUE;
    }
    bindAddress = new InetSocketAddress(bindIp, bindPort);
    this.accepts = url.getParameter(ACCEPTS_KEY, DEFAULT_ACCEPTS);
    this.idleTimeout = url.getParameter(IDLE_TIMEOUT_KEY, DEFAULT_IDLE_TIMEOUT);
    try {
    
    
        doOpen();
        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);
    }
    //fixme replace this with better method
    DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
    executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
}

NettyServer#doOpen
初始化开启一个NettyServer。
boss线程组的线程数默认是1;worker线程组的线程数是处理器数+1。

int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32);

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

    bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
    workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
            new DefaultThreadFactory("NettyServerWorker", true));

    final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
    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 {
    
    
                    // FIXME: should we use getTimeout()?
                    int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
                    NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                    ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
                            .addLast("decoder", adapter.getDecoder())
                            .addLast("encoder", adapter.getEncoder())
                            .addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS))
                            .addLast("handler", nettyServerHandler);
                }
            });
    // bind
    ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
    channelFuture.syncUninterruptibly();
    channel = channelFuture.channel();

}

RegistryProtocol#register
这里获得的registry是ZookeeperRegistry。ZookeeperRegistry是FailbackRegistry的子类,会调用FailbackRegistry的注册方法。

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

FailbackRegistry#register
FailbackRegistry是AbstractRegistry的子类,super.register调用的是父类的注册方法,把这个url放入一个集合中。
FailbackRegistry的doRegister方法是一个模板抽象方法,没有具体的实现。这里调用的还是实现类ZookeeperRegistry的实现。

public void register(URL url) {
    
    
   super.register(url);
    removeFailedRegistered(url);
    removeFailedUnregistered(url);
    try {
    
    
        // Sending a registration request to the server side
        doRegister(url);
    } catch (Exception e) {
    
    
       //省略
    }
}

ZookeeperRegistry#doRegister 是调用Zookeeper客户端去创建节点,也就是注册服务。

public void doRegister(URL url) {
    
    
    try {
    
    
        zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));
    } catch (Throwable e) {
    
    
        throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

猜你喜欢

转载自blog.csdn.net/u012734723/article/details/121186385