dubbo服务导出

dubbo版本:2.7.2

一、spring解析自定义扩展标签。

spring分析xml节点的可以看出对于自定义命名空间的节点使用的是自定义的NameSpaceHandler处理的。

在spring初始化的时候,创建DefaultBeanDefinitionDocumentReader的时候,指明了会从META-INF/spring.handlers中加载各类自定义扩展标签对应的处理器。

    public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
        this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
    }

在dubbo的jar包里有META-INF/spring.handlers制定了dubbo命名空间的namespaceHandler。

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

DefaultBeanDefinitionDocumentReader

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                                                // 自定义命名空间在这里解析
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
// 这里会获得之前从dubbo的META-INF/spring.handlers加载的dubbo命名空间解析器
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

针对每一个dubbo自定义标签注册乐解析器。除了annotation注解,解析器都是DubboBeanDefinitionParser。DubboBeanDefinitionParser(ApplicationConfig.class, true)第一个参数是最终会解析成的bean的类型,第二个参数是否required。

除了service、reference、config-center标签会解析成Bean类,其他都是解析成Cofig类。因为这三个比较复杂。

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

}

DubboBeanDefinitionParser的parse方法,都是一些把配置文件分析成BeanDefinition的逻辑,普通的spring bean 在parse阶段也是分析成beanDefinition,beanDefinition到最终的注入spring的bean需要执行哪些逻辑,就看bean实现了哪些spring的接口了。

private static BeanDefinition parse(Element element, ParserContext parserContext, Class beanClass, boolean required) {

所以先看service标签对应的ServiceBean类。

InitializingBean接口:初始化bean后会调用afterPropertiesSet方法。

DisposableBean接口:销毁bean会调用destroy方法。这里什么都没做。

ApplicationContextAware接口:注入applicationContext对象。

ApplicationListener接口:事件发布。

其他的aware接口:都是注入spring的对象。

public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean,
        ApplicationContextAware, ApplicationListener, BeanNameAware,
        ApplicationEventPublisherAware

先看afterPropertiesSet方法。

serviceBean继承了ServiceConfig,ServiceConfig继承很多Config类。因为很多类都需要比如application、registries、protocal这些配置信息,而且公用了很多配置信息相关的逻辑。所以产生这么多层继承关系。

afterPropertiesSet就是从spring容器获取providerConfigs、application、module、Registry、等等,然后填充成员变量,便于后续使用。


image.png

截取一部分代码

public void afterPropertiesSet() throws Exception {
        // 第一次provider肯定是空
        if (getProvider() == null) {
            // 从spring容器中获取ProviderConfig类
            Map providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
            if (providerConfigMap != null && providerConfigMap.size() > 0) {
                Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
                if (CollectionUtils.isEmptyMap(protocolConfigMap)
                        && providerConfigMap.size() > 1) { // backward compatibility
                    List providerConfigs = new ArrayList();
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() != null && config.isDefault()) {
                            providerConfigs.add(config);
                        }
                    }
                    if (!providerConfigs.isEmpty()) {
                        // 赋值到config成员变量中
                        setProviders(providerConfigs);
                    }
                } else {
                    ProviderConfig providerConfig = null;
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault()) {
                            if (providerConfig != null) {
                                throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
                            }
                            providerConfig = config;
                        }
                    }
                    if (providerConfig != null) {
                        setProvider(providerConfig);
                    }
                }
            }
            
            ...一系列类似的从spring中获取dubbo所需的配置类填充config成员变量
            
            // 如果不支持事件发布,这里就直接export导出服务。因为一般导出服务是在事件监听中做的
            
             if (!supportedApplicationListener) {
                export();
            }
        }

事件监听方法,监听spring refresh事件,这里导出服务。

@Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (!isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            export();
        }
    }
     @Override
    public void export() {
        super.export();
        // Publish ServiceBeanExportedEvent
        publishExportEvent();
    }
    
     public synchronized void export() {
        // 检查更新配置信息,这里就是一些校验和一些赋值配置信息逻辑,链接注册中心,暂时不看
        checkAndUpdateSubConfigs();
        // 是否export,因为dubbo服务可以配置export=false
        if (!shouldExport()) {
            return;
        }
        // 是否延迟导出,延迟就是简单的定时器
        if (shouldDelay()) {
            delayExportExecutor.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
        } else {
            doExport();
        }
    }
    
    private void doExportUrls() {
        // 根据之前已经afterPropertiesSet方法已经填充好的的成员变量registry注册中心对象,再根据application、prtocal等构造一个URL对象。
        // 如:registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=first-dubbo-provider&dubbo=2.0.2&pid=21772®istry=zookeeper&release=2.7.2×tamp=1635649541098
        
        List registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            // 如果group和version不为空,protocal的contextPath也不为空,则根据他们组装成pathKey 
            // 为空则还是path:org.apache.dubbo.samples.api.GreetingsService
            String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
            // providerModel,每提供的一个服务service类,封装成一个providerModel模型,providerModel会把service类相关信息serviceName、serviceInstance、serviceInterfaceClass、methods解析和维护起来
            ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
            // ApplicationModel是以key,value形式维护providerModel
            ApplicationModel.initProviderModel(pathKey, providerModel);
            // 真正导出服务
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

导出服务:可以预见两步:1、先netty开启端口暴露服务,使得其他服务可以调用。2、把服务url注册到zookeeper上。

 protocolConfig自然是前面解析配置文件的时候的Dubbo协议。
 registryURLs只有一个::registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=first-dubboprovider&dubbo=2.0.2&pid=21772®istry=zookeeper&release=2.7.2×tamp=1635649541098
 
 private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {
    String name = protocolConfig.getName();
        if (StringUtils.isEmpty(name)) {
            name = DUBBO;
        }
        // 把各种配置参数放到map
        Map map = new HashMap();
        map.put(SIDE_KEY, PROVIDER_SIDE);

        appendRuntimeParameters(map);
        appendParameters(map, metrics);
        appendParameters(map, application);
        appendParameters(map, module);
        // remove 'default.' prefix for configs from ProviderConfig
        // appendParameters(map, provider, Constants.DEFAULT_KEY);
        appendParameters(map, provider);
        appendParameters(map, protocolConfig);
        appendParameters(map, this);
        // methods是否为空。配置的时候,里面可以显示指定method。指定了解析的时候就会给methods赋值。这里没有
        if (CollectionUtils.isNotEmpty(methods)) {
        
        }
        // 是否是一般协议,这里是false。不管
        if (ProtocolUtils.isGeneric(是否是一般协议,这里是false。不管)) {
            map.put(GENERIC_KEY, generic);
            map.put(METHODS_KEY, ANY_VALUE);
        }else {
            // 如果配置了版本这里就添加版本,这里没配置跳过。
            String revision = Version.getVersion(interfaceClass, version);
            if (revision != null && revision.length() > 0) {
                map.put(REVISION_KEY, revision);
            }
            // Wrapper会动态javassiter生成代理类。代理类包含了很多类参数,比如methodName就是其中一个参数,反射扫描类的所有方法。最后添加到map中。
            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("No method found in service interface " + interfaceClass.getName());
                map.put(METHODS_KEY, ANY_VALUE);
            } else {
                map.put(METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
            }
        }
        
    // 构造export的服务url,根据之前获取的各种参数
    
    // 获取host和port,细节不看
       String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        Integer port = this.findConfigedPorts(protocolConfig, name, map);
        // 构造url。name是dubbo。所以构造的是dubbo协议的url。把map中的参数添加到url中。
        //url如下: dubbo://192.168.106.1:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&bind.ip=192.168.106.1&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=30496®ister=true&release=2.7.2&side=provider×tamp=1635651181724
        URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" +               path).orElse(path), map);
// 如果有协议对应的扩展配置工厂,会对url进行重写。默认没有
  if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }
// 导出范围。有remote: 远程、local:jvm内部。默认两个都发布
String scope = url.getParameter(SCOPE_KEY);
        // don't export when none is configured
        if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
                // 导出本地不看
                exportLocal(url);
            }
            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
                if (CollectionUtils.isNotEmpty(registryURLs)) {
                    for (URL registryURL : registryURLs) {
                        ...
                        // 前面都是写拼装url。registryURL是registry协议:registry://
                        
                        // Invoker类是可适配扩展类,默认是javassistProxyFactory类:proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

                        // 这里构建invoker代理。传参:ref-真正实现类。interfaceClass-接口。还有一个url:url把registry协议的url和dubbo协议的url参数合并了。最终还是一个registry协议的url。
                        // Invoker类,有这三个变量的get方法。所以spi生成的适配器代理,会根据invoker.getUrl获取url,在根据url的动态参数调用指定实现类的方法。
                        // invoker类还有一个invoker。invoker方法可以可以看成普通的代理方法。调用包装的实现类的方法。
                        Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
                        // 对invoker和ServiceConfig再包一层
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                        // protocol是适配器扩展类。 protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
                        // 因为wrapperInvoker.getUrl.getProtocol获取的是registry。所以这里实际调用的RegistryProtocol的export方法
                        Exporter exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                
 }

接下来走到了RegistryProtocol的exprot方法。

@Override
    public  Exporter export(final Invoker originInvoker) throws RpcException {
        // 获取registry协议的url。registry://
        URL registryUrl = getRegistryUrl(originInvoker);
        // url to export locally
        // 获取dubbo协议的url。dubbo://
        URL providerUrl = getProviderUrl(originInvoker);
        // 下面url的订阅重写不看
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);

        providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
        //export invoker
        // 真正暴露服务,也就是暴露Invoker。originInvoker是封装了接口、接口实现类、url的invoker类,外面还包了一层的DelegateProviderMetaDataInvoker类。providerUrl是dubbo协议的url。
        final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl);

        // url to registry
        final Registry registry = getRegistry(originInvoker);
        final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
        ProviderInvokerWrapper 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);
    }
 private  ExporterChangeableWrapper doLocalExport(final Invoker originInvoker, URL providerUrl) {
        // 从registry协议获取到的key是:dubbo://192.168.106.1:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&bind.ip=192.168.106.1&bind.port=20880&deprecated=false&dubbo=2.0.2&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=16556®ister=true&release=2.7.2&side=provider×tamp=1635736295334
        String key = getCacheKey(originInvoker);
// bounds以key为url,value是ExporterChangeableWrapper的形式缓存了暴露的服务。
// computeIfAbsent方法就是说bounds没有就执行,执行的结果添加到bounds。
        return (ExporterChangeableWrapper) bounds.computeIfAbsent(key, s -> {
            // 又包了一层
            Invoker invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
            // protocol.export是真正暴露服务。暴露之后获取到Exporter类,然后和registry协议的invoker再封装成ExporterChangeableWrapper缓存起来。
            // protocol是可适配扩展类。会根据invokerDelegate的url选择调用哪个实现类的方法。invokerDelegate的getUrl方法获取到的协议自然是dubbo协议。所以这里按道理是调用DubboProtocol的export方法。
            // 但是其实这里还有个小细节。并非直接调用DubboProtocol的export方法,因为DubboProtocol在SPi加载的时候,外面包裹了三层Wrapper。具体往下看
            return new ExporterChangeableWrapper<>((Exporter) protocol.export(invokerDelegate), originInvoker);
        });
    }

当ExtensionLoader.getExtension("dubbo")的时候,调用如下方法获取扩展类的时候。

 private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz);
        } 
          // 如果存在参数是class的构造方法,就说是Wrapper类,缓存起来。
        else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        }
}

private T createExtension(String name) {
        Class clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            // cachedWrapperClasses前面会缓存三个ProtocolFilterWrapper、ProtocolListenerWrapper、QosProtocolWrapper。
            Set> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
            // 这里会三个Wrapper一级一级包装
                for (Class wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

有三个Wrapper类:ProtocolFilterWrapper、ProtocolListenerWrapper、QosProtocolWrapper。三个

public class ProtocolFilterWrapper implements Protocol {

    private final Protocol protocol;

    public ProtocolFilterWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }
public class ProtocolListenerWrapper implements Protocol {

    private final Protocol protocol;

    public ProtocolListenerWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }
    
    public class QosProtocolWrapper implements Protocol {

    private final Logger logger = LoggerFactory.getLogger(QosProtocolWrapper.class);

    private static AtomicBoolean hasStarted = new AtomicBoolean(false);

    private Protocol protocol;

    public QosProtocolWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }

来到DubboProtocol的export方法

public  Exporter export(Invoker invoker) throws RpcException {
        // dubbo协议的url
        URL url = invoker.getUrl();
        // 从url中分析出可以:org.apache.dubbo.samples.api.GreetingsService:20880
        String key = serviceKey(url);
        // 封装一个exproter
        DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
        exporterMap.put(key, exporter);
        // url中是否指明是回调服务和子事件。这里没有不管
        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;
    }
private void openServer(URL url) {
        //key为192.168.106.1:20880,当前服务的地址和端口
        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是Map,缓存了一下
                        serverMap.put(key, createServer(url));
                    }
                }
            } else {
                // server supports reset, use together with override
                server.reset(url);
            }
        }
    }
private ExchangeServer createServer(URL 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();
         // DEFAULT_REMOTING_SERVER是netty。没有指定则默认是是netty服务
        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 {
        // dubbo专门封装了一个ExchangeServer来绑定url的服务
            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 supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
            if (!supportedTypes.contains(str)) {
                throw new RpcException("Unsupported client type: " + str);
            }
        }

        return server;
    }
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");
        // getExchange是适配器扩展,默认是HeaderExchange
        return getExchanger(url).bind(url, handler);
    }
@Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        // HeaderExchangeServer包裹了bind之后的Server对象,HeaderExchangeServer效果是能对Server对象进行健康检测好像
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }
 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);
        }
        // getTransporter获取适配器扩展,通过url参数动态调用实现类方法,这里默认是netty
        return getTransporter().bind(url, handler);
    }
    
    public class NettyTransporter implements Transporter {

    public static final String NAME = "netty";

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

后面就是正常的创建netty 服务了。就是熟悉的netty代码了。

public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
        super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
    }

    @Override
    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() {
                    @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的export方法

@Override
    public  Exporter export(final Invoker originInvoker) throws RpcException {
        // 服务导出
        final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl);
        // 下面就是服务注册,这里获得的Zookeeper协议url:zookeeper://
        // 自然这里获得的就是ZookeeperRegistry
        final Registry registry = getRegistry(originInvoker);
        // 如果registryUrl中有simplified参数,说明url需要精简,就会把providerUrl有关filter的参数都去掉,默认是要精简
        final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
        // 这里把invoker和url地址缓存了一下
        ProviderInvokerWrapper providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
                registryUrl, registeredProviderUrl);
        //to judge if we need to delay publish
        boolean register = registeredProviderUrl.getParameter("register", true);
        if (register) {
            // 这里真正注册。registryUrl是zookeeper://,registerProviderUrl是dubbo://
            register(registryUrl, registeredProviderUrl);
            providerInvokerWrapper.setReg(true);
        }
        // 订阅url重写,先不管
        // Deprecated! Subscribe to override rules in 2.6.x or before.
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        // 注册之后,exporter set一下注册地址
        exporter.setRegisterUrl(registeredProviderUrl);
        exporter.setSubscribeUrl(overrideSubscribeUrl);
        //Ensure that a new exporter instance is returned every time export
        return new DestroyableExporter<>(exporter);
    }
private URL getRegistryUrl(Invoker originInvoker) {
        URL registryUrl = originInvoker.getUrl();
        if (REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
        // 因为registry协议url指定了registry参数是zookeeper,所以这里获得的协议就是zookeeper,如果没有指定就是dubbo协议 registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?...®istry=zookeeper&release=2.7.2×tamp=1635750787988
            String protocol = registryUrl.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY);
            registryUrl = registryUrl.setProtocol(protocol).removeParameter(REGISTRY_KEY);
        }
        return registryUrl;
    }
public void register(URL registryUrl, URL registeredProviderUrl) {
        // 可适配扩展,这里获得的自然是ZookeeperRegistry
        Registry registry = registryFactory.getRegistry(registryUrl);
        registry.register(registeredProviderUrl);
    }

ZookeeperRegistry构造方法会建立跟zookeeper的连接。

@SPI("curator")
public interface ZookeeperTransporter {

    @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
    ZookeeperClient connect(URL url);

}
// zookeeperTransporter是spi获取的,默认spi扩展类是curator
 public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
     ... 省略代码
// 建立连接
        zkClient = zookeeperTransporter.connect(url);
        zkClient.addStateListener(state -> {
            if (state == StateListener.RECONNECTED) {
                try {
                    recover();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        });
    }

public class CuratorZookeeperTransporter extends AbstractZookeeperTransporter {
    @Override
    public ZookeeperClient createZookeeperClient(URL url) {
        return new CuratorZookeeperClient(url);
    }

zookeeperRegistry的registry方法调用的是父类FailbackRegistry,顾名思义,快速失败注册器

public void register(URL url) {
        // 这里只是缓存添加了一份url
        super.register(url);
        // 下面两行代码,都是从failRegister中移除url,如果failRegister移除后不为空,则直接cancel取消。目的是当其他注册url失败了,则这里注册也马上取消,也就是快速失败的意思
        removeFailedRegistered(url);
        removeFailedUnregistered(url);
        try {
            // 这里真正注册。模板方法模式,子类ZookeeperRegistry调用。
            doRegister(url);
        } catch (Exception e) {
            // 注册异常了,就添加到failRegister集合,用于前面的快速失败
            // Record a failed registration request to a failed list, retry regularly
            addFailedRegistered(url);
        }
    }

可以看到,zookeeper的注册,就是在zookeeper建立一个临时路径节点。

@Override
   public void doRegister(URL url) {
       try {
           //zookeeper上创建的路径就是: /dubbo/org.apache.dubbo.samples.api.GreetingsService/providers/dubbo%3A%2F%2F192.168.106.1%3A20880%2Forg.apache.dubbo.samples.api.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.api.GreetingsService%26methods%3DsayHi%26pid%3D18400%26register%3Dtrue%26release%3D2.7.2%26side%3Dprovider%26timestamp%3D1635750787995
           // 第二个参数,是否是创建的节点是临时的,默认是true:url.getParameter(DYNAMIC_KEY, true)
           zkClient.create(toUrlPath(url), 
           );
       } catch (Throwable e) {
           throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
       }
   }

至此,导出和注册也就看完了。

你可能感兴趣的:(dubbo服务导出)