• Dubbo服务导出源码


    前言:Dubbo捐献给Apache后,已有一段时间,以前粗略看过2.5.4版的源码(官网现在好像已经找不到这个版本),现在重新研究下Dubbo源码并记录下,由于英文水平待提高,主要结合   中文官方文档   和源码。

    Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。整个逻辑大致可分为三个部分:

               第一部分是前置工作,主要用于检查参数,组装 URL。

               第二部分是导出服务,包含导出服务到本地 (JVM),和导出服务到远程两个过程。

               第三部分是向注册中心注册服务,用于服务发现。

                 服务导出的入口类是 ServiceBean,入口方法onApplicationEvent。

    public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
            ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware,
            ApplicationEventPublisherAware {
    
    
        private static final long serialVersionUID = 213195494150089726L;
    
        private final transient Service service;
    
        private transient ApplicationContext applicationContext;
    
        private transient String beanName;
    
        private transient boolean supportedApplicationListener;
    
        private ApplicationEventPublisher applicationEventPublisher;
    
        public ServiceBean() {
            super();
            this.service = null;
        }
    
        public ServiceBean(Service service) {
            super(service);
            this.service = service;
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
            SpringExtensionFactory.addApplicationContext(applicationContext);
            supportedApplicationListener = addApplicationListener(applicationContext, this);
        }
    
        @Override
        public void setBeanName(String name) {
            this.beanName = name;
        }
    
        /**
         * Gets associated {@link Service}
         *
         * @return associated {@link Service}
         */
        public Service getService() {
            return service;
        }
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            if (!isExported() && !isUnexported()) {
                if (logger.isInfoEnabled()) {
                    logger.info("The service ready on spring started. service: " + getInterface());
                }
                export();
            }
        }
    
        @Override
        @SuppressWarnings({"unchecked", "deprecation"})
        public void afterPropertiesSet() throws Exception {
            if (getProvider() == null) {
                Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
                if (providerConfigMap != null && providerConfigMap.size() > 0) {
                    Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
                    if (CollectionUtils.isEmptyMap(protocolConfigMap)
                            && providerConfigMap.size() > 1) { // backward compatibility
                        List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
                        for (ProviderConfig config : providerConfigMap.values()) {
                            if (config.isDefault() != null && config.isDefault()) {
                                providerConfigs.add(config);
                            }
                        }
                        if (!providerConfigs.isEmpty()) {
                            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);
                        }
                    }
                }
            }
            if (getApplication() == null
                    && (getProvider() == null || getProvider().getApplication() == null)) {
                Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
                if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
                    ApplicationConfig applicationConfig = null;
                    for (ApplicationConfig config : applicationConfigMap.values()) {
                        if (applicationConfig != null) {
                            throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                        }
                        applicationConfig = config;
                    }
                    if (applicationConfig != null) {
                        setApplication(applicationConfig);
                    }
                }
            }
            if (getModule() == null
                    && (getProvider() == null || getProvider().getModule() == null)) {
                Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
                if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
                    ModuleConfig moduleConfig = null;
                    for (ModuleConfig config : moduleConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault()) {
                            if (moduleConfig != null) {
                                throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                            }
                            moduleConfig = config;
                        }
                    }
                    if (moduleConfig != null) {
                        setModule(moduleConfig);
                    }
                }
            }
    
            if (StringUtils.isEmpty(getRegistryIds())) {
                if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) {
                    setRegistryIds(getApplication().getRegistryIds());
                }
                if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) {
                    setRegistryIds(getProvider().getRegistryIds());
                }
            }
    
            if ((CollectionUtils.isEmpty(getRegistries()))
                    && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getRegistries()))
                    && (getApplication() == null || CollectionUtils.isEmpty(getApplication().getRegistries()))) {
                Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
                if (CollectionUtils.isNotEmptyMap(registryConfigMap)) {
                    List<RegistryConfig> registryConfigs = new ArrayList<>();
                    if (StringUtils.isNotEmpty(registryIds)) {
                        Arrays.stream(COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> {
                            if (registryConfigMap.containsKey(id)) {
                                registryConfigs.add(registryConfigMap.get(id));
                            }
                        });
                    }
    
                    if (registryConfigs.isEmpty()) {
                        for (RegistryConfig config : registryConfigMap.values()) {
                            if (StringUtils.isEmpty(registryIds)) {
                                registryConfigs.add(config);
                            }
                        }
                    }
                    if (!registryConfigs.isEmpty()) {
                        super.setRegistries(registryConfigs);
                    }
                }
            }
            if (getMetadataReportConfig() == null) {
                Map<String, MetadataReportConfig> metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false);
                if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) {
                    super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next());
                } else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) {
                    throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap);
                }
            }
    
            if (getConfigCenter() == null) {
                Map<String, ConfigCenterConfig> configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class, false, false);
                if (configenterMap != null && configenterMap.size() == 1) {
                    super.setConfigCenter(configenterMap.values().iterator().next());
                } else if (configenterMap != null && configenterMap.size() > 1) {
                    throw new IllegalStateException("Multiple ConfigCenter found:" + configenterMap);
                }
            }
    
            if (getMonitor() == null
                    && (getProvider() == null || getProvider().getMonitor() == null)
                    && (getApplication() == null || getApplication().getMonitor() == null)) {
                Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
                if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                    MonitorConfig monitorConfig = null;
                    for (MonitorConfig config : monitorConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault()) {
                            if (monitorConfig != null) {
                                throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                            }
                            monitorConfig = config;
                        }
                    }
                    if (monitorConfig != null) {
                        setMonitor(monitorConfig);
                    }
                }
            }
    
            if (getMetrics() == null) {
                Map<String, MetricsConfig> metricsConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class, false, false);
                if (metricsConfigMap != null && metricsConfigMap.size() > 0) {
                    MetricsConfig metricsConfig = null;
                    for (MetricsConfig config : metricsConfigMap.values()) {
                        if (metricsConfig != null) {
                            throw new IllegalStateException("Duplicate metrics configs: " + metricsConfig + " and " + config);
                        }
                        metricsConfig = config;
                    }
                    if (metricsConfig != null) {
                        setMetrics(metricsConfig);
                    }
                }
            }
    
            if (StringUtils.isEmpty(getProtocolIds())) {
                if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) {
                    setProtocolIds(getProvider().getProtocolIds());
                }
            }
    
            if (CollectionUtils.isEmpty(getProtocols())
                    && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getProtocols()))) {
                Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
                if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                    List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
                    if (StringUtils.isNotEmpty(getProtocolIds())) {
                        Arrays.stream(COMMA_SPLIT_PATTERN.split(getProtocolIds()))
                                .forEach(id -> {
                                    if (protocolConfigMap.containsKey(id)) {
                                        protocolConfigs.add(protocolConfigMap.get(id));
                                    }
                                });
                    }
    
                    if (protocolConfigs.isEmpty()) {
                        for (ProtocolConfig config : protocolConfigMap.values()) {
                            if (StringUtils.isEmpty(protocolIds)) {
                                protocolConfigs.add(config);
                            }
                        }
                    }
    
                    if (!protocolConfigs.isEmpty()) {
                        super.setProtocols(protocolConfigs);
                    }
                }
            }
            if (StringUtils.isEmpty(getPath())) {
                if (StringUtils.isNotEmpty(beanName)
                        && StringUtils.isNotEmpty(getInterface())
                        && beanName.startsWith(getInterface())) {
                    setPath(beanName);
                }
            }
            if (!supportedApplicationListener) {
                export();
            }
        }
    
        /**
         * Get the name of {@link ServiceBean}
         *
         * @return {@link ServiceBean}'s name
         * @since 2.6.5
         */
        public String getBeanName() {
            return this.beanName;
        }
    
        /**
         * @since 2.6.5
         */
        @Override
        public void export() {
            super.export();
            // Publish ServiceBeanExportedEvent
            publishExportEvent();
        }
    
        /**
         * @since 2.6.5
         */
        private void publishExportEvent() {
            ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);
            applicationEventPublisher.publishEvent(exportEvent);
        }
    
        @Override
        public void destroy() throws Exception {
            // no need to call unexport() here, see
            // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener
        }
    
        // merged from dubbox
        @Override
        protected Class getServiceClass(T ref) {
            if (AopUtils.isAopProxy(ref)) {
                return AopUtils.getTargetClass(ref);
            }
            return super.getServiceClass(ref);
        }
    
        /**
         * @param applicationEventPublisher
         * @since 2.6.5
         */
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            this.applicationEventPublisher = applicationEventPublisher;
        }
    }
    View Code

               

                 

                  export 方法:开始导出服务

                  

               doExport方法:真正开始导出服务

        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。
    // ApplicationModel 持有所有的 ProviderModel。
    ProviderModel providerModel
    = new ProviderModel(pathKey, ref, interfaceClass); ApplicationModel.initProviderModel(pathKey, providerModel); doExportUrlsFor1Protocol(protocolConfig, registryURLs); } }

             loadRegistries作用:1.检测是否存在注册中心配置类,不存在则抛出异常  2.构建参数映射集合,也就是 map  3.构建注册中心链接列表   4.遍历链接列表,并根据条件决定是否将其添加到 registryList 中

        protected List<URL> loadRegistries(boolean provider) {
            // check && override if necessary
            List<URL> registryList = new ArrayList<URL>();
            if (CollectionUtils.isNotEmpty(registries)) {
                for (RegistryConfig config : registries) {
                    String address = config.getAddress();
                    if (StringUtils.isEmpty(address)) {
                        address = ANYHOST_VALUE;
                    }
                    if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                        Map<String, String> map = new HashMap<String, String>();
                        appendParameters(map, application);
                        appendParameters(map, config);
                        map.put(PATH_KEY, RegistryService.class.getName());
                        appendRuntimeParameters(map);
                        if (!map.containsKey(PROTOCOL_KEY)) {
                            map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
                        }
                        List<URL> urls = UrlUtils.parseURLs(address, map);
    
                        for (URL url : urls) {
                            url = URLBuilder.from(url)
                                    .addParameter(REGISTRY_KEY, url.getProtocol())
                                    .setProtocol(REGISTRY_PROTOCOL)
                                    .build();
                            if ((provider && url.getParameter(REGISTER_KEY, true))
                                    || (!provider && url.getParameter(SUBSCRIBE_KEY, true))) {
                                registryList.add(url);
                            }
                        }
                    }
                }
            }
            return registryList;
        }
    View Code

               doExportUrlsFor1Protocol:当前协议导出

               Dubbo服务注册是基于URL驱动的,该方法前半段是组装URL,后半段才是导出Dubbo服务。

       private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
            String name = protocolConfig.getName();
            if (StringUtils.isEmpty(name)) {
                name = DUBBO;
            }
    
            Map<String, String> map = new HashMap<String, String>();
            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);
            if (CollectionUtils.isNotEmpty(methods)) {
                for (MethodConfig method : methods) {
                    appendParameters(map, method, method.getName());
                    String retryKey = method.getName() + ".retry";
                    if (map.containsKey(retryKey)) {
                        String retryValue = map.remove(retryKey);
                        if (Boolean.FALSE.toString().equals(retryValue)) {
                            map.put(method.getName() + ".retries", "0");
                        }
                    }
                    List<ArgumentConfig> arguments = method.getArguments();
                    if (CollectionUtils.isNotEmpty(arguments)) {
                        for (ArgumentConfig argument : arguments) {
                            // convert argument type
                            if (argument.getType() != null && argument.getType().length() > 0) {
                                Method[] methods = interfaceClass.getMethods();
                                // visit all methods
                                if (methods != null && methods.length > 0) {
                                    for (int i = 0; i < methods.length; i++) {
                                        String methodName = methods[i].getName();
                                        // target the method, and get its signature
                                        if (methodName.equals(method.getName())) {
                                            Class<?>[] argtypes = methods[i].getParameterTypes();
                                            // one callback in the method
                                            if (argument.getIndex() != -1) {
                                                if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
                                                    appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                                                } else {
                                                    throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                                }
                                            } else {
                                                // multiple callbacks in the method
                                                for (int j = 0; j < argtypes.length; j++) {
                                                    Class<?> argclazz = argtypes[j];
                                                    if (argclazz.getName().equals(argument.getType())) {
                                                        appendParameters(map, argument, method.getName() + "." + j);
                                                        if (argument.getIndex() != -1 && argument.getIndex() != j) {
                                                            throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            } else if (argument.getIndex() != -1) {
                                appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                            } else {
                                throw new IllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
                            }
    
                        }
                    }
                } // end of methods for
            }
    
            if (ProtocolUtils.isGeneric(generic)) {
                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);
                }
    
                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<String>(Arrays.asList(methods)), ","));
                }
            }
            if (!ConfigUtils.isEmpty(token)) {
                if (ConfigUtils.isDefault(token)) {
                    map.put(TOKEN_KEY, UUID.randomUUID().toString());
                } else {
                    map.put(TOKEN_KEY, token);
                }
            }
            // export service
            String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
            Integer port = this.findConfigedPorts(protocolConfig, name, map);
            URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
    
            if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .hasExtension(url.getProtocol())) {
                url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                        .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
            }
    
            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)
                if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
                    exportLocal(url);
                }
                // export to remote if the config is not local (export to local only when config is 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.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);
                        }
                    } 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);
        }
    View Code

               根据 url 中的 scope 参数决定服务导出方式,分别如下:1.scope = none,不导出服务  2.scope != remote,导出到本地   3.scope != local,导出到远程

               不管是导出到本地,还是远程。进行服务导出之前,均需要先创建 Invoker,这是一个很重要的步骤。因此下面先来分析 Invoker 的创建过程。

               Invoker 创建过程:在 Dubbo 中,Invoker 是一个非常重要的模型。在服务提供端,以及服务引用端均会出现 Invoker。Dubbo 官方文档中对 Invoker 进行了说明,这里引用一下。Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

               Invoker 是由 ProxyFactory 创建而来,Dubbo 默认的 ProxyFactory 实现类是 JavassistProxyFactory。(基于Dubbo的SPI动态适配)

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // 为目标类创建 Wrapper
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        // 创建匿名 Invoker 类对象,并实现 doInvoke 方法。
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 调用 Wrapper 的 invokeMethod 方法,invokeMethod 最终会调用目标方法
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

                Wrapper 是一个抽象类,仅可通过 getWrapper(Class) 方法创建子类。在创建 Wrapper 子类的过程中,子类代码生成逻辑会对 getWrapper 方法传入的 Class 对象进行解析,拿到诸如类方法,类成员变量等信息。以及生成 invokeMethod 方法代码和其他一些方法代码。代码生成完毕后,通过 Javassist 生成 Class 对象,最后再通过反射创建 Wrapper 实例。相关的代码如下:

    public static Wrapper getWrapper(Class<?> c) {    
        while (ClassGenerator.isDynamicClass(c))
            c = c.getSuperclass();
    
        if (c == Object.class)
            return OBJECT_WRAPPER;
    
        // 从缓存中获取 Wrapper 实例
        Wrapper ret = WRAPPER_MAP.get(c);
        if (ret == null) {
            // 缓存未命中,创建 Wrapper
            ret = makeWrapper(c);
            // 写入缓存
            WRAPPER_MAP.put(c, ret);
        }
        return ret;
    }

           makeWrapper 方法

      private static Wrapper makeWrapper(Class<?> c) {
            if (c.isPrimitive()) {
                throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
            }
    
            String name = c.getName();
            ClassLoader cl = ClassUtils.getClassLoader(c);
    
            StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
            StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
            StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
    
            c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    
            Map<String, Class<?>> pts = new HashMap<>(); // <property name, property types>
            Map<String, Method> ms = new LinkedHashMap<>(); // <method desc, Method instance>
            List<String> mns = new ArrayList<>(); // method names.
            List<String> dmns = new ArrayList<>(); // declaring method names.
    
            // get all public field.
            for (Field f : c.getFields()) {
                String fn = f.getName();
                Class<?> ft = f.getType();
                if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) {
                    continue;
                }
    
                c1.append(" if( $2.equals("").append(fn).append("") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
                c2.append(" if( $2.equals("").append(fn).append("") ){ return ($w)w.").append(fn).append("; }");
                pts.put(fn, ft);
            }
    
            Method[] methods = c.getMethods();
            // get all public method.
            boolean hasMethod = hasMethods(methods);
            if (hasMethod) {
                c3.append(" try{");
                for (Method m : methods) {
                    //ignore Object's method.
                    if (m.getDeclaringClass() == Object.class) {
                        continue;
                    }
    
                    String mn = m.getName();
                    c3.append(" if( "").append(mn).append("".equals( $2 ) ");
                    int len = m.getParameterTypes().length;
                    c3.append(" && ").append(" $3.length == ").append(len);
    
                    boolean override = false;
                    for (Method m2 : methods) {
                        if (m != m2 && m.getName().equals(m2.getName())) {
                            override = true;
                            break;
                        }
                    }
                    if (override) {
                        if (len > 0) {
                            for (int l = 0; l < len; l++) {
                                c3.append(" && ").append(" $3[").append(l).append("].getName().equals("")
                                        .append(m.getParameterTypes()[l].getName()).append("")");
                            }
                        }
                    }
    
                    c3.append(" ) { ");
    
                    if (m.getReturnType() == Void.TYPE) {
                        c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
                    } else {
                        c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
                    }
    
                    c3.append(" }");
    
                    mns.add(mn);
                    if (m.getDeclaringClass() == c) {
                        dmns.add(mn);
                    }
                    ms.put(ReflectUtils.getDesc(m), m);
                }
                c3.append(" } catch(Throwable e) { ");
                c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
                c3.append(" }");
            }
    
            c3.append(" throw new " + NoSuchMethodException.class.getName() + "("Not found method \""+$2+"\" in class " + c.getName() + "."); }");
    
            // deal with get/set method.
            Matcher matcher;
            for (Map.Entry<String, Method> entry : ms.entrySet()) {
                String md = entry.getKey();
                Method method = entry.getValue();
                if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                    String pn = propertyName(matcher.group(1));
                    c2.append(" if( $2.equals("").append(pn).append("") ){ return ($w)w.").append(method.getName()).append("(); }");
                    pts.put(pn, method.getReturnType());
                } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                    String pn = propertyName(matcher.group(1));
                    c2.append(" if( $2.equals("").append(pn).append("") ){ return ($w)w.").append(method.getName()).append("(); }");
                    pts.put(pn, method.getReturnType());
                } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                    Class<?> pt = method.getParameterTypes()[0];
                    String pn = propertyName(matcher.group(1));
                    c1.append(" if( $2.equals("").append(pn).append("") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
                    pts.put(pn, pt);
                }
            }
            c1.append(" throw new " + NoSuchPropertyException.class.getName() + "("Not found property \""+$2+"\" field or setter method in class " + c.getName() + "."); }");
            c2.append(" throw new " + NoSuchPropertyException.class.getName() + "("Not found property \""+$2+"\" field or setter method in class " + c.getName() + "."); }");
    
            // make class
            long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
            ClassGenerator cc = ClassGenerator.newInstance(cl);
            cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
            cc.setSuperClass(Wrapper.class);
    
            cc.addDefaultConstructor();
            cc.addField("public static String[] pns;"); // property name array.
            cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
            cc.addField("public static String[] mns;"); // all method name array.
            cc.addField("public static String[] dmns;"); // declared method name array.
            for (int i = 0, len = ms.size(); i < len; i++) {
                cc.addField("public static Class[] mts" + i + ";");
            }
    
            cc.addMethod("public String[] getPropertyNames(){ return pns; }");
            cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
            cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
            cc.addMethod("public String[] getMethodNames(){ return mns; }");
            cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
            cc.addMethod(c1.toString());
            cc.addMethod(c2.toString());
            cc.addMethod(c3.toString());
    
            try {
                Class<?> wc = cc.toClass();
                // setup static field.
                wc.getField("pts").set(null, pts);
                wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
                wc.getField("mns").set(null, mns.toArray(new String[0]));
                wc.getField("dmns").set(null, dmns.toArray(new String[0]));
                int ix = 0;
                for (Method m : ms.values()) {
                    wc.getField("mts" + ix++).set(null, m.getParameterTypes());
                }
                return (Wrapper) wc.newInstance();
            } catch (RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                cc.release();
                ms.clear();
                mns.clear();
                dmns.clear();
            }
        }
    View Code

            导出服务到远程:Exporter<?> exporter = protocol.export(wrapperInvoker);

            包含了服务导出与服务注册两个过程。这两个过程涉及到了大量的调用,比较复杂。按照代码执行顺序,本节先来分析服务导出逻辑,服务注册逻辑将在下一节进行分析。下面开始分析,我们把目光移动到 RegistryProtocol 的 export 方法上。

        @Override
        public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
            // 获取注册中心 URL,以 zookeeper 注册中心为例,得到的示例 URL 如下:
            // zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&export=dubbo%3A%2F%2F172.17.48.52%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider
            URL registryUrl = getRegistryUrl(originInvoker);
            
            URL providerUrl = getProviderUrl(originInvoker);
            // 获取订阅 URL,比如:
            // provider://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?category=configurators&check=false&anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
            final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
            // 创建监听器
            final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
            overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
    
            providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
            // 导出服务
            final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
    
            // 根据 URL 加载 Registry 实现类,比如 ZookeeperRegistry
            final Registry registry = getRegistry(originInvoker);
            // 获取已注册的服务提供者 URL,比如:
            // dubbo://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
            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);
            }
    
            // 向注册中心进行订阅 override 数据
            registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
    
            exporter.setRegisterUrl(registeredProviderUrl);
            exporter.setSubscribeUrl(overrideSubscribeUrl);
            // 创建并返回 DestroyableExporter
            return new DestroyableExporter<>(exporter);
        }

               doLocalExport 方法的逻辑

        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);
    //此处的 protocol 变量会在运行时加载 DubboProtocol,并调用 DubboProtocol 的 export 方法
    return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker); }); }
         DubboProtocol的export逻辑
        public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
            URL url = invoker.getUrl();
    
            // 获取服务标识,理解成服务坐标也行。由服务组名,服务名,服务版本号以及端口组成。比如:
            // demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
            String key = serviceKey(url);
            // 创建 DubboExporter
            DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
            // 将 <key, exporter> 键值对放入缓存中
            exporterMap.put(key, exporter);
    
            // 本地存根相关代码
            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;
        }

               DubboExporter 的创建以及 openServer 方法逻辑

    private void openServer(URL url) {
        // 获取 host:port,并将其作为服务器实例的 key,用于标识当前的服务器实例
        String key = url.getAddress();
        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
        if (isServer) {
            // 访问缓存
            ExchangeServer server = serverMap.get(key);
            if (server == null) {
                // 创建服务器实例
                serverMap.put(key, createServer(url));
            } else {
                // 服务器已创建,则根据 url 中的配置重置服务器
                server.reset(url);
            }
        }
    }

            在同一台机器上(单网卡),同一个端口上仅允许启动一个服务器实例。若某个端口上已有服务器实例,此时则调用 reset 方法重置服务器的一些配置

           createServer方法逻辑:三个核心的逻辑。第一是检测是否存在 server 参数所代表的 Transporter 拓展,不存在则抛出异常。第二是创建服务器实例。第三是检测是否支持 client 参数所表示的 Transporter 拓展,不存在也是抛出异常。

        private ExchangeServer createServer(URL url) {
            url = URLBuilder.from(url)
                    // 服务器关闭时发送readonly事件,默认情况下启用
                    .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
                    // 添加心跳检测配置到 url 中
                    .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
                    // 添加编码解码器参数
                    .addParameter(CODEC_KEY, DubboCodec.NAME)
                    .build();
            //获取 server 参数,默认为 netty
            String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
            // 通过 SPI 检测是否存在 server 参数所代表的 Transporter 拓展,不存在则抛出异常
            if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
                throw new RpcException("Unsupported server type: " + str + ", url: " + url);
            }
    
            ExchangeServer server;
            try {
                // 创建 ExchangeServer
                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) {
                // 获取所有的 Transporter 实现类名称集合,比如 supportedTypes = [netty, mina]
                Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
                // 检测当前 Dubbo 所支持的 Transporter 实现类名称列表中,
                // 是否包含 client 所表示的 Transporter,若不包含,则抛出异常
                if (!supportedTypes.contains(str)) {
                    throw new RpcException("Unsupported client type: " + str);
                }
            }
    
            return server;
        }

              bind逻辑

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

             getExchanger逻辑:Exchanger的自定扩展点

        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绑定逻辑

        @Override
        public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
            return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
        }
        Transporters.bind绑定逻辑
        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 {
    // 如果 handlers 元素数量大于1,则创建 ChannelHandler 分发器
                handler = new ChannelHandlerDispatcher(handlers);
            }
     // 获取自适应 Transporter 实例,并调用实例方法
            return getTransporter().bind(url, handler);
        }

             getTransporter() 方法获取的 Transporter 是在运行时动态创建的,类名为 TransporterAdaptive,也就是自适应拓展类。TransporterAdaptive 会在运行时根据传入的 URL 参数决定加载什么类型的 Transporter,默认为 NettyTransporter。

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

            NettyServer的构造:构造NettyServer

    public class NettyServer extends AbstractServer implements Server {
        public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
            // 调用父类构造方法
            super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
        }
    }
    
    
    public abstract class AbstractServer extends AbstractEndpoint implements Server {
        public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
            // 调用父类构造方法,这里就不用跟进去了,没什么复杂逻辑
            super(url, handler);
            localAddress = getUrl().toInetSocketAddress();
    
            // 获取 ip 和端口
            String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());
            int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());
            if (url.getParameter(Constants.ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {
                // 设置 ip 为 0.0.0.0
                bindIp = NetUtils.ANYHOST;
            }
            bindAddress = new InetSocketAddress(bindIp, bindPort);
            // 获取最大可接受连接数
            this.accepts = url.getParameter(Constants.ACCEPTS_KEY, Constants.DEFAULT_ACCEPTS);
            this.idleTimeout = url.getParameter(Constants.IDLE_TIMEOUT_KEY, Constants.DEFAULT_IDLE_TIMEOUT);
            try {
                // 调用模板方法 doOpen 启动服务器
                doOpen();
            } catch (Throwable t) {
                throw new RemotingException("Failed to bind ");
            }
    
            DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
            executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
        }
        
        protected abstract void doOpen() throws Throwable;
    
        protected abstract void doClose() throws Throwable;
    }

           doOpen 抽象方法,该方法需要子类(NettyServer )实现:熟悉Netty这段代码应该不难

    protected void doOpen() throws Throwable {
        NettyHelper.setNettyLoggerFactory();
        // 创建 boss 和 worker 线程池
        ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
        
        // 创建 ServerBootstrap
        bootstrap = new ServerBootstrap(channelFactory);
    
        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
        channels = nettyHandler.getChannels();
        bootstrap.setOption("child.tcpNoDelay", true);
        // 设置 PipelineFactory
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() {
                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                ChannelPipeline pipeline = Channels.pipeline();
                pipeline.addLast("decoder", adapter.getDecoder());
                pipeline.addLast("encoder", adapter.getEncoder());
                pipeline.addLast("handler", nettyHandler);
                return pipeline;
            }
        });
        // 绑定到指定的 ip 和端口上
        channel = bootstrap.bind(getBindAddress());
    }

            注意下:dubbo 默认使用的 NettyServer 是基于 netty 3.x 版本实现的,比较老了。因此 Dubbo 另外提供了 netty 4.x 版本的 NettyServer

           服务导出的过程就基本结束

         

         服务注册流程:服务注册操作对于 Dubbo 来说不是必需的,通过服务直连的方式就可以绕过注册中心。但通常我们不会这么做,直连方式不利于服务治理,仅推荐在测试服务时使用。对于 Dubbo 来说,注册中心虽不是必需,但却是必要的。

         默认 Zookeeper 注册中心作为分析目标。下面从服务注册的入口方法开始分析,我们把目光再次移到 RegistryProtocol 的 export 方法上。

          register(registryUrl, registeredProviderUrl) 逻辑

    public void register(URL registryUrl, URL registedProviderUrl) {
        // 获取 Registry
        Registry registry = registryFactory.getRegistry(registryUrl);
        // 注册服务
        registry.register(registedProviderUrl);
    }

            registryFactory.getRegistry(registryUrl):方法由 AbstractRegistryFactory 实现

    public Registry getRegistry(URL url) {
        url = url.setPath(RegistryService.class.getName())
                .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
                .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
        String key = url.toServiceString();
        LOCK.lock();
        try {
            // 访问缓存
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            
            // 缓存未命中,创建 Registry 实例
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry...");
            }
            
            // 写入缓存
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            LOCK.unlock();
        }
    }

              createRegistry逻辑:ZookeeperRegistryFactory 实现

    public class ZookeeperRegistryFactory extends AbstractRegistryFactory {
    
        private ZookeeperTransporter zookeeperTransporter;
    
        /**
         * Invisible injection of zookeeper client via IOC/SPI
         * @param zookeeperTransporter
         */
        public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
            this.zookeeperTransporter = zookeeperTransporter;
        }
    
        @Override
        public Registry createRegistry(URL url) {
            return new ZookeeperRegistry(url, zookeeperTransporter);
        }
    
    }

            new ZookeeperRegistry(***)代码实现:创建zk注册

    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() {
            @Override
            public void stateChanged(int state) {
                if (state == RECONNECTED) {
                    try {
                        recover();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        });
    }

           zookeeperTransporter 类型为自适应拓展类,因此 connect 方法会在被调用时决定加载什么类型的 ZookeeperTransporter 拓展,默认为 CuratorZookeeperTransporter

          Curator:对zk操作的框架

    public class CuratorZookeeperClient extends AbstractZookeeperClient<CuratorWatcher> {
    
        private final CuratorFramework client;
        
        public CuratorZookeeperClient(URL url) {
            super(url);
            try {
                // 创建 CuratorFramework 构造器
                CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                        .connectString(url.getBackupAddress())
                        .retryPolicy(new RetryNTimes(1, 1000))
                        .connectionTimeoutMs(5000);
                String authority = url.getAuthority();
                if (authority != null && authority.length() > 0) {
                    builder = builder.authorization("digest", authority.getBytes());
                }
                // 构建 CuratorFramework 实例
                client = builder.build();
                // 添加监听器
                client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
                    @Override
                    public void stateChanged(CuratorFramework client, ConnectionState state) {
                        if (state == ConnectionState.LOST) {
                            CuratorZookeeperClient.this.stateChanged(StateListener.DISCONNECTED);
                        } else if (state == ConnectionState.CONNECTED) {
                            CuratorZookeeperClient.this.stateChanged(StateListener.CONNECTED);
                        } else if (state == ConnectionState.RECONNECTED) {
                            CuratorZookeeperClient.this.stateChanged(StateListener.RECONNECTED);
                        }
                    }
                });
                
                // 启动客户端
                client.start();
            } catch (Exception e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
        }
    }

             再回到RegistryProtocol中的register方法

            registry.register方法:方法定义在 FailbackRegistry 抽象类

    public void register(URL url) {
        super.register(url);
        failedRegistered.remove(url);
        failedUnregistered.remove(url);
        try {
            // 模板方法,由子类实现
            doRegister(url);
        } catch (Exception e) {
            Throwable t = e;
    
            // 获取 check 参数,若 check = true 将会直接抛出异常
            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                    && url.getParameter(Constants.CHECK_KEY, true)
                    && !Constants.CONSUMER_PROTOCOL.equals(url.getProtocol());
            boolean skipFailback = t instanceof SkipFailbackWrapperException;
            if (check || skipFailback) {
                if (skipFailback) {
                    t = t.getCause();
                }
                throw new IllegalStateException("Failed to register");
            } else {
                logger.error("Failed to register");
            }
    
            // 记录注册失败的链接
            failedRegistered.add(url);
        }
    }

            doRegister方法:zk注册

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

             create 方法:zk客户端的代码

    public void create(String path, boolean ephemeral) {
        if (!ephemeral) {
            // 如果要创建的节点类型非临时节点,那么这里要检测节点是否存在
            if (checkExists(path)) {
                return;
            }
        }
        int i = path.lastIndexOf('/');
        if (i > 0) {
            // 递归创建上一级路径
            create(path.substring(0, i), false);
        }
        
        // 根据 ephemeral 的值创建临时或持久节点
        if (ephemeral) {
            createEphemeral(path);
        } else {
            createPersistent(path);
        }
    }

             服务注册整个过程可简单总结为:先创建注册中心实例,之后再通过注册中心实例注册服务。

           节点创建后再zk中体现:通过 Zookeeper 可视化客户端 ZooInspector 查看节点数据

         





        

  • 相关阅读:
    ffmpeg命令行获取RTSP流并每秒截取一张解码存储为jpg
    快速排序
    ffmpeg参数中文详细解释
    Docker
    elasticsearch的安装和配置
    C 语言-运算符(算术运算符,类型转换,赋值运算符,自增,自减,sizeof 运算符,逗号运算符,关系运算符,逻辑运算符,三目运算符)
    c语言-printf函数和scanf函数简单使用
    将JPA通用的实现方法封装成一个抽象类进行拓展
    工具类里的静态变量如何获取application.yml或者application.properties里的属性
    记java实体类属性名为全部为大写踩的坑(基础)
  • 原文地址:https://www.cnblogs.com/dyg0826/p/11334233.html
Copyright © 2020-2023  润新知