dubbo 源码解析(1)----- 服务发布

dubbo如何集成spring

通常我们在配置文件添加以下配置就能发布一个服务, 并把服务注册在注册中心中, 下面我们来查看dubbo如何通过下面的配置文件与spring进行集成


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                           http://dubbo.apache.org/schema/dubbo
                           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="hello-world-app"  />

    <!-- 使用multicast广播注册中心暴露服务地址 -->
    <dubbo:registry protocol="zookeeper"  address="192.168.239.102:2181" />

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol  name="dubbo" port="-1" />

    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.czj.rpc.api.UserApi" ref="userApi" >
    </dubbo:service>

    <dubbo:service loadbalance="" interface="com.czj.rpc.api.OrderApi" ref="orderApi" >
    </dubbo:service>
    
</beans>

在dubbo依赖中包含了META-INF/spring.handlers文件, 该文件是spring对自定义schema解析的配置文件扩展,内容如下:

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

DubboNamespaceHandler主要对dubbo的所有标签注册不同的解析配置


public class DubboNamespaceHandler extends NamespaceHandlerSupport {

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

    @Override
    public void init() {
        /**
        往spring注册不同的标签解析,DubboBeanDefinitionParser是dubbo通用的
        标签解析类, 里面主要的工作原理为:
        1、生成 RootBeanDefinition ,  把入参的class赋值到beanClass属性中
        2、使用parserContext.getRegistry().registerBeanDefinition()
           往IOC容器注册创建的BeanDefinition 
        3、根据入参的Class类型为RootBeanDefinition赋值propertyValues
        **/
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.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());
    }

}


与spring集成到这里结束, 下面我们重点关注 ServiceBean 这个Bean是发布服务的关键类

解析ServiceBean

什么时候开始发布服务


public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
    
    /**
    
    该类实现了 InitializingBean ,在IOC容器对该类实例化后, 会调用 afterPropertiesSet 方法,
    此时 ServiceBean  将会进行服务的发布工作


    **/
    public void afterPropertiesSet() throws Exception {
        
        /**
         检测 ProviderConfig provider 是否为空, 为空的话将从IOC容器从获取
         ProviderConfig 类型的bean对象,并赋值给当前对象的provider属性
        **/
        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 ((protocolConfigMap == null || protocolConfigMap.size() == 0)
                        && providerConfigMap.size() > 1) { // backward compatibility
                    List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() != null && config.isDefault().booleanValue()) {
                            providerConfigs.add(config);
                        }
                    }
                    if (!providerConfigs.isEmpty()) {
                        setProviders(providerConfigs);
                    }
                } else {
                    ProviderConfig providerConfig = null;
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault().booleanValue()) {
                            if (providerConfig != null) {
                                throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
                            }
                            providerConfig = config;
                        }
                    }
                    if (providerConfig != null) {
                        setProvider(providerConfig);
                    }
                }
            }
        }
        
        /**
         检测 ApplicationConfig application 是否为空, 为空的话将从IOC容器从获取
         ApplicationConfig 类型的bean对象,并赋值给当前对象的 application 属性
        **/
        
        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 (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if (applicationConfig != null) {
                            throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                        }
                        applicationConfig = config;
                    }
                }
                if (applicationConfig != null) {
                    setApplication(applicationConfig);
                }
            }
        }
        
        
        /**
             检测 ModuleConfig module 是否为空, 为空的话将从IOC容器从获取
             ModuleConfig 类型的bean对象,并赋值给当前对象的 module 属性
        **/
        
        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().booleanValue()) {
                        if (moduleConfig != null) {
                            throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                        }
                        moduleConfig = config;
                    }
                }
                if (moduleConfig != null) {
                    setModule(moduleConfig);
                }
            }
        }
        
        
        /**
             重要:获取注册中心的配置bean
             检测 List<RegistryConfig> registries  是否为空, 为空的话将从IOC容器从获取
             RegistryConfig 类型的bean对象,并赋值给当前对象的 registries 属性
        **/
        if ((getRegistries() == null || getRegistries().isEmpty())
                && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty())
                && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
            Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
            if (registryConfigMap != null && registryConfigMap.size() > 0) {
                List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
                for (RegistryConfig config : registryConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        registryConfigs.add(config);
                    }
                }
                if (registryConfigs != null && !registryConfigs.isEmpty()) {
                    super.setRegistries(registryConfigs);
                }
            }
        }
        
        /**
             检测 MonitorConfig monitor 是否为空, 为空的话将从IOC容器从获取
             MonitorConfig 类型的bean对象,并赋值给当前对象的 monitor 属性
        **/
        
        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().booleanValue()) {
                        if (monitorConfig != null) {
                            throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                        }
                        monitorConfig = config;
                    }
                }
                if (monitorConfig != null) {
                    setMonitor(monitorConfig);
                }
            }
        }
        
         /**
             检测 List<ProtocolConfig> protocols 是否为空, 为空的话将从IOC容器从获取
             ProtocolConfig 类型的bean对象,并赋值给当前对象的 protocols 属性
        **/
        
        if ((getProtocols() == null || getProtocols().isEmpty())
                && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) {
            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>();
                for (ProtocolConfig config : protocolConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        protocolConfigs.add(config);
                    }
                }
                if (protocolConfigs != null && !protocolConfigs.isEmpty()) {
                    super.setProtocols(protocolConfigs);
                }
            }
        }
        if (getPath() == null || getPath().length() == 0) {
            if (beanName != null && beanName.length() > 0
                    && getInterface() != null && getInterface().length() > 0
                    && beanName.startsWith(getInterface())) {
                setPath(beanName);
            }
        }
        
        /**
        如果设置的非延迟导出,则直接进行发布服务
        **/
        if (!isDelay()) {
            //最终进行导出服务的方法为 doExport
            export();
        }
    }
    
}

    

解析 doExport


protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        if (exported) {
            return;
        }
        exported = true;
		//判断用户是否有填写interface属性值,没有则抛出异常
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
        }
		
		/**
			检查provider 是否有在配置文件中配置<dubbo:provider> 如果没配置则new一个ProviderConfig实例,
			并遍历实例中的所有set方法,从系统变量中获取key名称=dubbo.{class}.{paramter} 的值,如果不为空则赋值到set方法中
		**/
        checkDefault();
		
		/**
			检测 provider是否为空,不为空判断 application   module registries monitor  protocols 是否为空, 为空从provider中取出对应字段覆盖
		**/
        if (provider != null) {
            if (application == null) {
                application = provider.getApplication();
            }
            if (module == null) {
                module = provider.getModule();
            }
            if (registries == null) {
                registries = provider.getRegistries();
            }
            if (monitor == null) {
                monitor = provider.getMonitor();
            }
            if (protocols == null) {
                protocols = provider.getProtocols();
            }
        }
		
		/**
			检测 module 是否为空,不为空判断  registries monitor 是否为空, 为空从 module 中取出对应字段覆盖
		**/
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
		
		/**
			检测 application 是否为空,不为空判断  registries monitor 是否为空, 为空从 module 中取出对应字段覆盖
		**/
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
		
		/**
			检测 ref 是否为泛化服务类型
		**/
        if (ref instanceof GenericService) {
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {
				//根据<dubbo:service interace=""> 的属性值获取Class对象,并赋值给 interfaceClass 属性
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
			//检查 interfaceClass 和 <dubbo:service><dubbo:method name="xxx"></dubbo:method></dubbo:service> 里的MethodConfig 是否有差异
            checkInterfaceAndMethods(interfaceClass, methods);
			//检查ref是否有值 并且 是否是 interfaceClass 的实现类
            checkRef();
            generic = Boolean.FALSE.toString();
        }
		
		//忽略
        if (local != null) {
            if ("true".equals(local)) {
                local = interfaceName + "Local";
            }
            Class<?> localClass;
            try {
                localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if (!interfaceClass.isAssignableFrom(localClass)) {
                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
            }
        }
        if (stub != null) {
            if ("true".equals(stub)) {
                stub = interfaceName + "Stub";
            }
            Class<?> stubClass;
            try {
                stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if (!interfaceClass.isAssignableFrom(stubClass)) {
                throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
		//检查 ApplicationConfig 是否为空
        checkApplication();
		//检查配置中心是否为空
        checkRegistry();
		//检查protocols 是否为空, 为空的话默认创建一个 ProtocolConfig , 并且赋值 name 为 "dubbo"
        checkProtocol();
		//遍历ServiceConfig实例中的所有set方法,从系统变量中获取key名称=dubbo.{class}.{paramter} 的值,如果不为空则赋值到set方法中
        appendProperties(this);
		//忽略
        checkStubAndMock(interfaceClass);
		//如果path为空, 则使用接口名字赋值给path
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
		// 导出服务
        doExportUrls();
        ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
        ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
    }

解析 doExportUrls

private void doExportUrls() {
    /**
     dubbo提供多种注册中心的实现, 具体使用哪一种注册中心,是根据URL的参数进行选择,
     所以URL是dubbo参数的承载,下面的 loadRegistries 是根据用户配置的
     RegistryConfig 转成 一组URL ,让dubbo知道要使用哪种注册中心的实现
    **/
    List<URL> registryURLs = loadRegistries(true);
    
    //根据用户配置的 ProtocolConfig 组装 URL 进行服务导出
    for (ProtocolConfig protocolConfig : protocols) {
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}
    
    

解析 loadRegistries


protected List<URL> loadRegistries(boolean provider) {
		//检查 registries 是否为空
        checkRegistry();
        List<URL> registryList = new ArrayList<URL>();
        if (registries != null && !registries.isEmpty()) {
			//遍历 registries
            for (RegistryConfig config : registries) {
				//获取配置中心的ip:port
                String address = config.getAddress();
				//如果地址为空, 使用 0.0.0.0
                if (address == null || address.length() == 0) {
                    address = Constants.ANYHOST_VALUE;
                }
				
				//获取系统变量dubbo.registry.address不为空, 则优先使用系统变量
                String sysaddress = System.getProperty("dubbo.registry.address");
                if (sysaddress != null && sysaddress.length() > 0) {
                    address = sysaddress;
                }
				
				
				//如果地址不为空, 开始组装 com.alibaba.dubbo.common.URL
                if (address.length() > 0 && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
					//构造一个Map用于参数的承载
                    Map<String, String> map = new HashMap<String, String>();
					//遍历 ApplicationConfig application  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
                    appendParameters(map, application);
					//遍历 RegistryConfig config  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
                    appendParameters(map, config);
					//添加path=com.alibaba.dubbo.registry.RegistryService
                    map.put("path", RegistryService.class.getName());
					//添加dubbo的版本号
                    map.put("dubbo", Version.getProtocolVersion());
					//添加发布服务的时间
                    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
					//添加进程id
                    if (ConfigUtils.getPid() > 0) {
                        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                    }
					//如果配置中心没配置 <dubbo:registry protocol="xx"> protocol值
                    if (!map.containsKey("protocol")) {
						//则查看RegistryFactory自适应扩展点是否包含remote
                        if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                            map.put("protocol", "remote");
                        } else {
							//不存在remote扩展点, 则赋值dubbo作为protocol参数值
                            map.put("protocol", "dubbo");
                        }
                    }
					//根据地址和map,构造一组URL
                    List<URL> urls = UrlUtils.parseURLs(address, map);
                    for (URL url : urls) {
						//为url添加registry参数值为URL的协议值
                        url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
						//重新设置url的协议值为registry
                        url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
						//最后的url的内容为:
						//registry://192.168.239.102:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&dubbo=2.0.2&pid=33456&registry=zookeeper&timestamp=1578627774870
                        if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                                || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }
    

解析 doExportUrlsFor1Protocol


private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        String name = protocolConfig.getName();
		 // 如果协议名为空,或空串,则将协议名变量设置为 dubbo
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }
		
		//构造一个Map用作参数承载
        Map<String, String> map = new HashMap<String, String>();
		// 添加 side到 map 中
        map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
		// 添加 dubbo版本号 到 map 中
        map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
		// 添加 时间戳 到 map 中
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
		
		// 添加 进程id 到 map 中
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
		//遍历  application  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
        appendParameters(map, application);
		//遍历  module  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
        appendParameters(map, module);
		//遍历  provider  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
        appendParameters(map, provider, Constants.DEFAULT_KEY);
		//遍历  protocolConfig  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
        appendParameters(map, protocolConfig);
		//遍历  ServiceConfig  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中
        appendParameters(map, this);
		
		/**
		遍历<dubbo:method>的配置信息, 并遍历  MethodConfig  所有的get方法,并且返回值是基本数据类型,并且不为空,则放入map中,
		key的前缀为 ${methodName}.${params}
		**/
        if (methods != null && !methods.isEmpty()) {
            for (MethodConfig method : methods) {
                appendParameters(map, method, method.getName());
                String retryKey = method.getName() + ".retry";
                if (map.containsKey(retryKey)) {
                    String retryValue = map.remove(retryKey);
                    if ("false".equals(retryValue)) {
                        map.put(method.getName() + ".retries", "0");
                    }
                }
                List<ArgumentConfig> arguments = method.getArguments();
                if (arguments != null && !arguments.isEmpty()) {
                    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
        }

		// 检测 generic 是否为 "true",并根据检测结果向 map 中添加不同的信息
        if (ProtocolUtils.isGeneric(generic)) {
            map.put(Constants.GENERIC_KEY, generic);
            map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
        } else {
			//获取服务的版本号
            String revision = Version.getVersion(interfaceClass, version);
			//版本号不为空则往map追加版本号信息
            if (revision != null && revision.length() > 0) {
                map.put("revision", revision);
            }
			//为接口生成包裹类 Wrapper,Wrapper 中包含了接口的详细信息,比如接口方法名数组,字段信息等
            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
			// 添加方法名到 map 中,如果包含多个方法名,则用逗号隔开,比如 method = init,destroy
            if (methods.length == 0) {
                logger.warn("NO method found in service interface " + interfaceClass.getName());
                map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
            } else {
                map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }	
        }
		// 添加 token 到 map 中
        if (!ConfigUtils.isEmpty(token)) {
            if (ConfigUtils.isDefault(token)) {
				// 随机生成 token
                map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString());
            } else {
                map.put(Constants.TOKEN_KEY, token);
            }
        }
		
		// 判断协议名是否为 injvm
        if (Constants.LOCAL_PROTOCOL.equals(protocolConfig.getName())) {
            protocolConfig.setRegister(false);
            map.put("notify", "false");
        }
		
        // 获取上下文路径
        String contextPath = protocolConfig.getContextpath();
        if ((contextPath == null || contextPath.length() == 0) && provider != null) {
            contextPath = provider.getContextpath();
        }

		// 获取对外开放的 ip和端口号
        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        Integer port = this.findConfigedPorts(protocolConfig, name, map);
		//根据协议、ip、端口、接口全名和参数Map构造导出服务URL
		/**
			默认使用dubbo协议的URL内容为:
			dubbo://192.168.251.37:20880/com.czj.rpc.api.UserApi?anyhost=true&application=hello-world-app
			&bind.ip=192.168.251.37&bind.port=20880&dubbo=2.0.2&generic=false
			&interface=com.czj.rpc.api.UserApi&methods=getName,get,save&pid=41080&side=provider&timestamp=1578635962790
		**/
        URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + 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(Constants.SCOPE_KEY);
        // don't export when none is configured
		// 如果scope属性为none则什么都不作
        if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            // export to local if the config is not remote (export to remote only when config is remote)
			//如果scope不等于remote,则把服务仅导出到本地,只供程序内本地调用, 一般配置文件的scope不填, 所以会导出到本地
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            // export to remote if the config is not local (export to local only when config is local)
			//如果scope不等于 local,导出到远程,  一般配置文件的scope不填, 所以会导出到远程
            if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                }
                if (registryURLs != null && !registryURLs.isEmpty()) {
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
						//加载监控中心URL参数
                        URL monitorUrl = loadMonitor(registryURL);
						
                        if (monitorUrl != null) {
							//如果有监控中心的配置, 往发布服务的URL追加 monitor 参数, 并进行URLEncoding
                            url = url.addParameterAndEncoded(Constants.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(Constants.PROXY_KEY);
                        if (StringUtils.isNotEmpty(proxy)) {
							//如果声明了, 需要往注册中心URL追加proxy配置
                            registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
                        }
						
						/**
						    在这里做了2个事情
						    1、在registerUrl里添加一个export的参数, 值为导出服务URL
						    老registerUrl内容:registry://192.168.239.102:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&dubbo=2.0.2&pid=8344&registry=zookeeper&timestamp=1578881953003
						    
						    新registerUrl内容:registry://192.168.239.102:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.241.15%3A20880%2Fcom.czj.rpc.api.UserApi%3Fanyhost%3Dtrue%26application%3Dhello-world-app%26bind.ip%3D192.168.241.15%26bind.port%3D20880%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dcom.czj.rpc.api.UserApi%26methods%3DgetName%2Cget%2Csave%26pid%3D8344%26side%3Dprovider%26timestamp%3D1578881953008&pid=8344&registry=zookeeper&timestamp=1578881953003
						    
						    2、创建一个Invoker
							Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,
							它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现
							
							在这里invoker 是一个本地的实现,  默认是由 JavassistProxyFactory 生成的
							ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension().getInvoker();
							生成的,  这里使用的是Dubbo SPI 生成的自适应类。 根据入参的URL参数动态调用ProxyFactory具体的实现类
							这里给出ExtensionLoader.getExtensionLoader(ProxyFactory.class)动态生成的部分源码:
							
							public class ProxyFactory$Adaptive implements com.alibaba.dubbo.rpc.ProxyFactory {
    

								public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0,
									java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)
									throws com.alibaba.dubbo.rpc.RpcException {
									if (arg2 == null) {
										throw new IllegalArgumentException("url == null");
									}

									com.alibaba.dubbo.common.URL url = arg2;
									//extName为具体的扩展点, 扩展点的获取从url中获取proxy的值, 默认值使用 javassist, 为什么会按照此规则, 可以去官网看Dubbo SPI的源码导读
									String extName = url.getParameter("proxy", "javassist");

									if (extName == null) {
										throw new IllegalStateException(
											"Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" +
											url.toString() + ") use keys([proxy])");
									}

									com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class)
																																	   .getExtension(extName);

									return extension.getInvoker(arg0, arg1, arg2);
								}
						}
						**/
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
						//对invoker做个包装
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

						
						
						/**
						 导出服务到远程
						**/
                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

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

Invoker 创建过程

JavassistProxyFactory

下面我们到 JavassistProxyFactory 代码中,探索 Invoker 的创建过程


public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
    

如上,JavassistProxyFactory 创建了一个继承自 AbstractProxyInvoker 类的匿名对象,并覆写了抽象方法 doInvoke。覆写后的 doInvoke 逻辑比较简单,仅是将调用请求转发给了 Wrapper 类的 invokeMethod 方法。Wrapper 用于“包裹”目标类,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;
}


getWrapper 方法仅包含一些缓存操作逻辑,不难理解。下面我们看一下 makeWrapper 方法。


private static Wrapper makeWrapper(Class<?> c) {
    // 检测 c 是否为基本类型,若是则抛出异常
    if (c.isPrimitive())
        throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

    String name = c.getName();
    ClassLoader cl = ClassHelper.getClassLoader(c);

    // c1 用于存储 setPropertyValue 方法代码
    StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
    // c2 用于存储 getPropertyValue 方法代码
    StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
    // c3 用于存储 invokeMethod 方法代码
    StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

    // 为Wrapper的3个方法生成类型转换代码及异常捕捉代码,比如:
    //   DemoService w; try { w = ((DemoServcie) $1); }}catch(Throwable e){ throw new IllegalArgumentException(e); }
    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); }");

    // pts 用于存储 成员变量名和类型、 get/set/is打头的方法名和返回类型
    Map<String, Class<?>> pts = new HashMap<String, Class<?>>();
    // ms 用于存储方法描述信息(可理解为方法签名)及 Method 实例
    Map<String, Method> ms = new LinkedHashMap<String, Method>();
    // mns 为方法名列表
    List<String> mns = new ArrayList<String>();
    // dmns 用于存储“定义在当前类中的方法”的名称
    List<String> dmns = new ArrayList<String>();

    // --------------------------------✨ 分割线1 ✨-------------------------------------

    // 获取 public 访问级别的字段,并为所有字段生成条件判断语句
    for (Field f : c.getFields()) {
        String fn = f.getName();
        Class<?> ft = f.getType();
        if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
            // 忽略关键字 static 或 transient 修饰的变量
            continue;

        // 生成条件判断及追加 setPropertyValue 方法构造语句,比如:
        // if( $2.equals("name") ) { w.name = (java.lang.String) $3; return;}
        // if( $2.equals("age") ) { w.age = ((Number) $3).intValue(); return;}
        c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");

        // 生成条件判断及返回语句 追加到 getPropertyValue 方法构造语句,比如:
        // if( $2.equals("name") ) { return ($w)w.name; }
        c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");

        // 存储 <字段名, 字段类型> 键值对到 pts 中
        pts.put(fn, ft);
    }

    // --------------------------------✨ 分割线2 ✨-------------------------------------

    Method[] methods = c.getMethods();
    // 检测 c 中的方法列表否为空, 排除掉Object的方法
    boolean hasMethod = hasMethods(methods);
    if (hasMethod) {
        c3.append(" try{");
    }
    for (Method m : methods) {
        if (m.getDeclaringClass() == Object.class)
            // 忽略 Object 中定义的方法
            continue;

        String mn = m.getName();
        // 生成方法名判断语句,比如:
        // if ( "sayHello".equals( $2 )
        c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
        int len = m.getParameterTypes().length;
        // 生成“运行时传入的参数数量与方法参数列表长度”判断语句,比如:
        // && $3.length == 2
        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;
            }
        }
        // 对重载方法进行处理,考虑下面的方法:
        //    1. void sayHello(Integer, String)
        //    2. void sayHello(Integer, Integer)
        // 方法名相同,参数列表长度也相同,因此不能仅通过这两项判断两个方法是否相等。
        // 需要进一步判断方法的参数类型
        if (override) {
            if (len > 0) {
                for (int l = 0; l < len; l++) {
                    // 生成参数类型进行检测代码,比如:
                    // && $3[0].getName().equals("java.lang.Integer") 
                    //    && $3[1].getName().equals("java.lang.String")
                    c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
                            .append(m.getParameterTypes()[l].getName()).append("\")");
                }
            }
        }

        // 添加 ) {,完成方法判断语句,此时生成的代码可能如下(已格式化):
        // if ("sayHello".equals($2) 
        //     && $3.length == 2
        //     && $3[0].getName().equals("java.lang.Integer") 
        //     && $3[1].getName().equals("java.lang.String")) {
        c3.append(" ) { ");

        // 根据返回值类型生成目标方法调用语句
        if (m.getReturnType() == Void.TYPE)
            // w.sayHello((java.lang.Integer)$4[0], (java.lang.String)$4[1]); return null;
            c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
        else
            // return w.sayHello((java.lang.Integer)$4[0], (java.lang.String)$4[1]);
            c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");

        // 添加 }, 生成的代码形如(已格式化):
        // if ("sayHello".equals($2) 
        //     && $3.length == 2
        //     && $3[0].getName().equals("java.lang.Integer") 
        //     && $3[1].getName().equals("java.lang.String")) {
        //
        //     w.sayHello((java.lang.Integer)$4[0], (java.lang.String)$4[1]); 
        //     return null;
        // }
        c3.append(" }");

        // 添加方法名到 mns 集合中
        mns.add(mn);
        // 检测当前方法是否在 c 中被声明的
        if (m.getDeclaringClass() == c)
            // 若是,则将当前方法名添加到 dmns 中
            dmns.add(mn);
        ms.put(ReflectUtils.getDesc(m), m);
    }
    if (hasMethod) {
        // 添加异常捕捉语句
        c3.append(" } catch(Throwable e) { ");
        c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
        c3.append(" }");
    }

    // 添加 NoSuchMethodException 异常抛出代码
    c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");

    // --------------------------------✨ 分割线3 ✨-------------------------------------

    Matcher matcher;
    // 处理 get/set 方法
    for (Map.Entry<String, Method> entry : ms.entrySet()) {
        String md = entry.getKey();
        Method method = (Method) entry.getValue();
        // 匹配以 get 开头的方法
        if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            // 获取属性名
            String pn = propertyName(matcher.group(1));
            // 生成属性判断以及返回语句,示例如下:
            // if( $2.equals("name") ) { return ($w).w.getName(); }
            c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
            pts.put(pn, method.getReturnType());

        // 匹配以 is/has/can 开头的方法
        } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            String pn = propertyName(matcher.group(1));
            // 生成属性判断以及返回语句,示例如下:
            // if( $2.equals("dream") ) { return ($w).w.hasDream(); }
            c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
            pts.put(pn, method.getReturnType());

        // 匹配以 set 开头的方法
        } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            Class<?> pt = method.getParameterTypes()[0];
            String pn = propertyName(matcher.group(1));
            // 生成属性判断以及 setter 调用语句,示例如下:
            // if( $2.equals("name") ) { w.setName((java.lang.String)$3); return; }
            c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
            pts.put(pn, pt);
        }
    }

    // 添加 NoSuchPropertyException 异常抛出代码
    c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
    c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");

    // --------------------------------✨ 分割线4 ✨-------------------------------------

    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;");
    cc.addField("public static " + Map.class.getName() + " pts;");
    cc.addField("public static String[] mns;");
    cc.addField("public static String[] dmns;");
    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();
        
        // 设置字段值
        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());

        // 创建 Wrapper 实例
        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();
    }
}

这里使用阿里开源 Java 应用诊断工具 Arthas 反编译代理dubbo动态生成Wrapper子类源码,内容如下




/**
 * Arthas 反编译步骤:
 * 1. 启动 Arthas
 *    java -jar arthas-boot.jar
 *
 * 2. 输入编号选择进程
 *    Arthas 启动后,会打印 Java 应用进程列表,如下:
	  [1]: 25892 com.czj.bootstrap.ProviderApplication
	  [2]: 8360
	  [3]: 25660 org.jetbrains.jps.cmdline.Launcher
	  [4]: 8124 org.jetbrains.idea.maven.server.RemoteMavenServer
 * 这里输入编号 1,让 Arthas 关联到启动类为 ProviderApplication 的 Java 进程上
 *
 * 3. 此时使用 sc 命令搜索这个Wrapper类名。
 *    $  sc *.Wrapper*
 *    com.alibaba.dubbo.common.bytecode.Wrapper
	  com.alibaba.dubbo.common.bytecode.Wrapper$1
	  com.alibaba.dubbo.common.bytecode.Wrapper0
	  com.alibaba.dubbo.common.bytecode.Wrapper1

 *
 * 4. 使用 jad 命令反编译 com.alibaba.dubbo.common.bytecode.Wrapper1
 *    $ jad com.alibaba.dubbo.common.bytecode.Wrapper1
 *
 * 更多使用方法请参考 Arthas 官方文档:
 *   https://alibaba.github.io/arthas/quick-start.html
 */
public class Wrapper1 extends Wrapper implements ClassGenerator.DC {
    public static String[] pns;
    public static Map pts;
    public static String[] mns;
    public static String[] dmns;
    public static Class[] mts0;
    public static Class[] mts1;
    public static Class[] mts2;
    public static Class[] mts3;

    @Override
    public String[] getPropertyNames() {
        return pns;
    }

    public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException {
        UserApiImpl userApiImpl;
        try {
            userApiImpl = (UserApiImpl)object;
        }
        catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        try {
            if ("get".equals(string) && arrclass.length == 1 && arrclass[0].getName().equals("java.lang.String")) {
                return userApiImpl.get((String)arrobject[0]);
            }
            if ("get".equals(string) && arrclass.length == 1 && arrclass[0].getName().equals("int")) {
                return userApiImpl.get(((Number)arrobject[0]).intValue());
            }
            if ("getName".equals(string) && arrclass.length == 0) {
                return userApiImpl.getName();
            }
            if ("setName".equals(string) && arrclass.length == 1) {
                userApiImpl.setName((String)arrobject[0]);
                return null;
            }
        }
        catch (Throwable throwable) {
            throw new InvocationTargetException(throwable);
        }
        throw new NoSuchMethodException(new StringBuffer().append("Not found method \"").append(string).append("\" in class com.czj.api.impl.UserApiImpl.").toString());
    }

    public Class getPropertyType(String string) {
        return (Class)pts.get(string);
    }

    @Override
    public void setPropertyValue(Object object, String string, Object object2) {
        UserApiImpl userApiImpl;
        try {
            userApiImpl = (UserApiImpl)object;
        }
        catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        if (string.equals("age")) {
            userApiImpl.age = ((Number)object2).intValue();
            return;
        }
        if (string.equals("name")) {
            userApiImpl.setName((String)object2);
            return;
        }
        throw new NoSuchPropertyException(new StringBuffer().append("Not found property \"").append(string).append("\" filed or setter method in class com.czj.api.impl.UserApiImpl.").toString());
    }

    @Override
    public Object getPropertyValue(Object object, String string) {
        UserApiImpl userApiImpl;
        try {
            userApiImpl = (UserApiImpl)object;
        }
        catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        if (string.equals("age")) {
            return new Integer(userApiImpl.age);
        }
        if (string.equals("name")) {
            return userApiImpl.getName();
        }
        throw new NoSuchPropertyException(new StringBuffer().append("Not found property \"").append(string).append("\" filed or setter method in class com.czj.api.impl.UserApiImpl.").toString());
    }

    @Override
    public String[] getMethodNames() {
        return mns;
    }

    @Override
    public String[] getDeclaredMethodNames() {
        return dmns;
    }

    @Override
    public boolean hasProperty(String string) {
        return pts.containsKey(string);
    }
}



导出服务到远程

分析具体调用哪个扩展点 Protocol



//
/**


	从上面的源码分析我们可以得到, 我们的URL为:
	registry://192.168.239.102:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&dubbo=2.0.2&pid=33456&registry=zookeeper&timestamp=1578627774870
	
	
	用刚才生成的invoker进行服务导出,  protocol 也是Dubbo SPI 生成的自适应类,
	根据动态生成的源码分析,会委派给扩展点为 registry 的 com.alibaba.dubbo.registry.integration.RegistryProtocol 去执行
	生成的源码如下:
	
	
**/

public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
   

		public com.alibaba.dubbo.rpc.Exporter export(
			com.alibaba.dubbo.rpc.Invoker arg0)
			throws com.alibaba.dubbo.rpc.RpcException {
			if (arg0 == null) {
				throw new IllegalArgumentException(
					"com.alibaba.dubbo.rpc.Invoker argument == null");
			}

			if (arg0.getUrl() == null) {
				throw new IllegalArgumentException(
					"com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
			}

			com.alibaba.dubbo.common.URL url = arg0.getUrl();
			// 扩展点为url的协议值, 如果为空默认为dubbo
			String extName = ((url.getProtocol() == null) ? "dubbo"
														  : url.getProtocol());

			if (extName == null) {
				throw new IllegalStateException(
					"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" +
					url.toString() + ") use keys([protocol])");
			}

			com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
																									   .getExtension(extName);

			return extension.export(arg0);
		}
}
	
Exporter<?> exporter = protocol.export(wrapperInvoker);


分析 RegistryProtocol.export


public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    // 导出远程服务
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

    // 省略下面往注册中心注册服务的代码, 这部分代码将在注册服务中讲解
}


上面代码看起来比较复杂,主要做如下一些操作:

  1. 调用 doLocalExport 导出服务
  2. 向注册中心注册服务
  3. 向注册中心进行订阅 override 数据
  4. 创建并返回 DestroyableExporter

在以上操作中,除了创建并返回 DestroyableExporter 没什么难度外,其他几步操作都不是很简单。这其中,导出服务和注册服务是本章要重点分析的逻辑。 订阅 override 数据并非本文重点内容,后面会简单介绍一下。下面先来分析 doLocalExport 方法的逻辑,如下:

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
    String key = getCacheKey(originInvoker);
    // 访问缓存
    ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
    if (exporter == null) {
        synchronized (bounds) {
            exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
            if (exporter == null) {
                
                /**
                创建 Invoker为委托类对象,在前面创建Invoker时,我们把导出服务的URL作为参数
                往注册URL的参数key为export赋值,在getProviderUrl()里是把export参数取出,并转为一个新的URL对象作为构造参数,传参到 InvokerDelegete
                
                此时invokerDelegete里的url值为:
                dubbo://192.168.241.15:20880/com.czj.rpc.api.UserApi?anyhost=true&application=hello-world-app&bind.ip=192.168.241.15&bind.port=20880&dubbo=2.0.2&generic=false&interface=com.czj.rpc.api.UserApi&methods=getName,get,save&pid=5888&side=provider&timestamp=1578882948296
                **/
                final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
                // 调用 protocol 的 export 方法导出服务, 这里的protocol 将会使用 DubboProtocol , 为什么使用DubboProtocol ,看前面生成的自适应类Protocol$Adaptive 源码 这里就不复述
                exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                
                // 写缓存
                bounds.put(key, exporter);
            }
        }
    }
    return exporter;
}

DubboProtocol

接下来我们目光转移到 DubboProtocol 的 export 方法上,相关分析如下:

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

    // 获取服务标识,理解成服务坐标也行。由服务组名,服务名,服务版本号以及端口组成。比如:
    // 这个key可以理解成MVC里的@RequestMapping 值 demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
    String key = serviceKey(url);
    // 创建 DubboExporter ,里面包含实际处理逻辑Invoker
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    //
    /**
     将 <com.czj.rpc.api.UserApi:20880, exporter> 键值对放入缓存中, 
     该缓存的主要作用在于接受到远程请求后, 会根据请求拼装成key,去命中 exporterMap 缓存,得到Invoker去处理远程请求
    **/
    exporterMap.put(key, exporter);

    // 本地存根相关代码
    Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
    Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
        String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
            // 省略日志打印代码
        } else {
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }

    // 启动服务器
    openServer(url);
    // 优化序列化
    optimizeSerialization(url);
    return exporter;
}

如上,我们重点关注 DubboExporter 的创建以及 openServer 方法,其他逻辑看不懂也没关系,不影响理解服务导出过程。另外,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 方法重置服务器的一些配置。考虑到篇幅问题,关于服务器实例重置的代码就不分析了。接下来分析服务器实例的创建过程。如下:


private ExchangeServer createServer(URL url) {
    url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY,
    // 添加心跳检测配置到 url 中
    url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
	// 获取 server 参数,默认为 netty
    String str = url.getParameter(Constants.SERVER_KEY, Constants.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);

    // 添加编码解码器参数
    url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
    ExchangeServer server;
    try {
        // 创建 ExchangeServer
        server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
        throw new RpcException("Fail to start server...");
    }
                                   
	// 获取 client 参数,可指定 netty,mina
    str = url.getParameter(Constants.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...");
        }
    }
    return server;
}


如上,createServer 包含三个核心的逻辑。第一是检测是否存在 server 参数所代表的 Transporter 拓展,不存在则抛出异常。第二是创建服务器实例。第三是检测是否支持 client 参数所表示的 Transporter 拓展,不存在也是抛出异常。两次检测操作所对应的代码比较直白了,无需多说。但创建服务器的操作目前还不是很清晰,我们继续往下看。


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");
    // 获取 Exchanger,默认为 HeaderExchanger。
    // 紧接着调用 HeaderExchanger 的 bind 方法创建 ExchangeServer 实例
    return getExchanger(url).bind(url, handler);
}

上面代码比较简单,就不多说了。下面看一下 HeaderExchanger 的 bind 方法。


public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
	// 创建 HeaderExchangeServer 实例,该方法包含了多个逻辑,分别如下:
	/**
		
		Transporters.bind() 开启一个对外服务的sever,new DecodeHandler(new HeaderExchangeHandler(handler)) 入参ChannelHandler
		的作用为:当有远程RPC请求后,由该ChannelHandler处理,该参数实际包含了3个 ChannelHandler,
		DecodeHandler:对请求数据包进行解码,转换为JavaBean对象
			|->HeaderExchangeHandler  把下一层ChannelHandler的最终调用结果组装成响应对象Response 并 , 注意:不是在这一层调用具体的服务接口实现
				|-> DubboProtocol.requestHandler   最终调用具体实现的处理器
		
		
	**/
	//   1. new HeaderExchangeHandler(handler)
	//	 2. new DecodeHandler(new HeaderExchangeHandler(handler))
	//   3. Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

查看如何开启server 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 实例,并调用实例方法,
    在自适应的源码我们可以看到,会从URL中取出参数名为server的值为扩展点的Transporter实例,如果server值为空,则默认使用netty扩展点的NettyTransporter实例
    
    **/
    return getTransporter().bind(url, handler);
}


/**

getTransporter() 方法获取的 Transporter 是在运行时动态创建的,类名为 Transporter$Adaptive 部分源码如下:

public class Transporter$Adaptive implements com.alibaba.dubbo.remoting.Transporter {
    

    public com.alibaba.dubbo.remoting.Server bind(
        com.alibaba.dubbo.common.URL arg0,
        com.alibaba.dubbo.remoting.ChannelHandler arg1)
        throws com.alibaba.dubbo.remoting.RemotingException {
        if (arg0 == null) {
            throw new IllegalArgumentException("url == null");
        }

        com.alibaba.dubbo.common.URL url = arg0;
        String extName = url.getParameter("server",
                url.getParameter("transporter", "netty"));

        if (extName == null) {
            throw new IllegalStateException(
                "Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" +
                url.toString() + ") use keys([server, transporter])");
        }

        com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.Transporter.class)
                                                                                                                   .getExtension(extName);

        return extension.bind(arg0, arg1);
    }
}



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



分析 NettyTransporter

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


这里仅有一句创建 NettyServer 的代码,无需多说,我们继续向下看。


public class NettyServer extends AbstractServer implements Server {
    public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
        // 调用父类构造方法,对handler做一个包装
        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 中。


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());
            /**
            具体业务处理,这个handler将会调用
            DecodeHandler:对请求数据包进行解码,转换为JavaBean对象
			|->HeaderExchangeHandler  把下一层ChannelHandler的最终调用结果组装成响应对象Response 并 , 注意:不是在这一层调用具体的服务接口实现
				|-> DubboProtocol.requestHandler   最终调用具体实现的处理器
            **/
            pipeline.addLast("handler", nettyHandler);
            return pipeline;
        }
    });
    // 绑定到指定的 ip 和端口上
    channel = bootstrap.bind(getBindAddress());
}


以上就是 NettyServer 创建的过程,在这里就不细讲netty的api描述,读者自行去了解,dubbo 默认使用的 NettyServer 是基于 netty 3.x 版本实现的,比较老了。因此 Dubbo 另外提供了 netty 4.x 版本的 NettyServer,大家可在使用 Dubbo 的过程中按需进行配置。

到此,关于服务导出的过程就分析完了,接下来分析服务导出的另一块逻辑 — 服务注册

服务注册

本节我们来分析服务注册过程,服务注册操作对于 Dubbo 来说不是必需的,通过服务直连的方式就可以绕过注册中心。但通常我们不会这么做,直连方式不利于服务治理,仅推荐在测试服务时使用。对于 Dubbo 来说,注册中心虽不是必需,但却是必要的。因此,关于注册中心以及服务注册相关逻辑,我们也需要搞懂。

本节内容以 Zookeeper 注册中心作为分析目标,其他类型注册中心大家可自行分析。下面从服务注册的入口方法开始分析,我们把目光再次移到 RegistryProtocol 的 export 方法上。如下:


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

    // ${导出服务} 上面我们已经讲过了
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

        
    // 获取注册中心 URL,把registry协议修改成URL参数 registry 的值, 以zookeeper 注册中心为例,得到的示例 URL 如下:
    /**
    registry://192.168.239.102:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&client=zkclient&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.241.15%3A20880%2Fcom.czj.rpc.api.UserApi%3Fanyhost%3Dtrue%26application%3Dhello-world-app%26bind.ip%3D192.168.241.15%26bind.port%3D20880%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dcom.czj.rpc.api.UserApi%26methods%3DgetName%2Cget%2Csave%26pid%3D12952%26side%3Dprovider%26timestamp%3D1578969221885&pid=12952&registry=zookeeper&timestamp=1578969221880
                ↓
    zookeeper://192.168.239.102:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&client=zkclient&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.241.15%3A20880%2Fcom.czj.rpc.api.UserApi%3Fanyhost%3Dtrue%26application%3Dhello-world-app%26bind.ip%3D192.168.241.15%26bind.port%3D20880%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dcom.czj.rpc.api.UserApi%26methods%3DgetName%2Cget%2Csave%26pid%3D12952%26side%3Dprovider%26timestamp%3D1578969221885&pid=12952&timestamp=1578969221880
    **/
    URL registryUrl = getRegistryUrl(originInvoker);

    // 根据 URL 加载 Registry 实现类,比如 ZookeeperRegistry
    final Registry registry = getRegistry(originInvoker);
    
    // 获取值已注册的服务提供者 URL,从export参数取出,比如:
    //dubbo://192.168.241.15:20880/com.czj.rpc.api.UserApi?anyhost=true&application=hello-world-app&dubbo=2.0.2&generic=false&interface=com.czj.rpc.api.UserApi&methods=getName,get,save&pid=12952&side=provider&timestamp=1578969221885
    final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker);

    // 获取 register 参数 ,该值是用于判断是否往注册中心注册服务
    boolean register = registeredProviderUrl.getParameter("register", true);

    // 向全局服务提供者缓存中注册服务提供者
    ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl);

    // 根据 register 的值决定是否注册远程服务
    if (register) {
        // 向注册中心注册服务
        register(registryUrl, registeredProviderUrl);
        //注册成功后, 取出缓存中的服务提供者,设置 reg 是否注册成功标识为true
        ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
    }

    // 获取订阅 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(registeredProviderUrl);
    // 创建监听器
    final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
    // 向注册中心进行订阅 override 数据
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
    // 创建并返回 DestroyableExporter
    return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);
}

分析服务注册逻辑,相关代码如下:


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


RegistryFactory registryFactory 是一个自适应的扩展类,由dubbo动态生成, 我们先反编译查看其源码:


public class RegistryFactory$Adaptive implements com.alibaba.dubbo.registry.RegistryFactory {
    public com.alibaba.dubbo.registry.Registry getRegistry(
        com.alibaba.dubbo.common.URL arg0) {
        if (arg0 == null) {
            throw new IllegalArgumentException("url == null");
        }

        com.alibaba.dubbo.common.URL url = arg0;
        String extName = ((url.getProtocol() == null) ? "dubbo"
                                                      : url.getProtocol());

        if (extName == null) {
            throw new IllegalStateException(
                "Fail to get extension(com.alibaba.dubbo.registry.RegistryFactory) name from url(" +
                url.toString() + ") use keys([protocol])");
        }

        com.alibaba.dubbo.registry.RegistryFactory extension = (com.alibaba.dubbo.registry.RegistryFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.registry.RegistryFactory.class)
                                                                                                                           .getExtension(extName);

        return extension.getRegistry(arg0);
    }
}



从源码我们可以得到, 我们最终调用的 Registry 实例对象为 ZookeeperRegistryFactory

分析ZookeeperRegistryFactory


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

}


public class ZookeeperRegistryFactory extends AbstractRegistryFactory {

    // zookeeperTransporter 由 SPI 在运行时注入,类型为 ZookeeperTransporter$Adaptive
    private ZookeeperTransporter zookeeperTransporter;

    public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
        this.zookeeperTransporter = zookeeperTransporter;
    }

    @Override
    public Registry createRegistry(URL url) {
        return new ZookeeperRegistry(url, zookeeperTransporter);
    }

}


ZookeeperTransporter 也是一个动态生成自适应扩展类, 源码如下:
可以看到,


public class ZookeeperTransporter$Adaptive implements com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter {
    public com.alibaba.dubbo.remoting.zookeeper.ZookeeperClient connect(
        com.alibaba.dubbo.common.URL arg0) {
        if (arg0 == null) {
            throw new IllegalArgumentException("url == null");
        }

        com.alibaba.dubbo.common.URL url = arg0;
        //会从URL取出client transporter的扩展点的实例,如果2个参数都为空, 默认使用curator扩展点
        String extName = url.getParameter("client",
                url.getParameter("transporter", "curator"));

        if (extName == null) {
            throw new IllegalStateException(
                "Fail to get extension(com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter) name from url(" +
                url.toString() + ") use keys([client, transporter])");
        }

        com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter.class)
                                                                                                                                                         .getExtension(extName);

        return extension.connect(arg0);
    }
}



继续跟进 ZookeeperRegistry 构造方法


public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
        super(url);
        if (url.isAnyHost()) {
            throw new IllegalStateException("registry address == null");
        }
         // 获取组名,默认为 dubbo
        String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
        if (!group.startsWith(Constants.PATH_SEPARATOR)) {
            group = 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 方法调用,这个方法用于创建 Zookeeper 客户端。创建好 Zookeeper 客户端,意味着注册中心的创建过程就结束了。接下来,再来分析一下 Zookeeper 客户端的创建过程。

前面说过,这里的 zookeeperTransporter 类型为自适应拓展类,因此 connect 方法会在被调用时决定加载什么类型的 ZookeeperTransporter 拓展,从上面的源码我们可以看到默认为 CuratorZookeeperTransporter。

分析CuratorZookeeperClient

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


CuratorZookeeperClient 构造方法主要用于创建和启动 CuratorFramework 实例。以上基本上都是 Curator 框架的代码,大家如果对 Curator 框架不是很了解,可以参考 Curator 官方文档。

本节分析了 ZookeeperRegistry 实例的创建过程,整个过程并不是很复杂。大家在看完分析后,可以自行调试,以加深理解。现在注册中心实例创建好了,接下来要做的事情是向注册中心注册服务,我们回到注册的入口代码。


public void register(URL registryUrl, URL registedProviderUrl) {
    // 获取 Registry 最终得到ZookeeperRegistry 上面的源码已经说了
    Registry registry = registryFactory.getRegistry(registryUrl);
    
    
    // 注册服务
    registry.register(registedProviderUrl);
}


开始分析registry.register(registedProviderUrl),因为ZookeeperRegistry是 FailbackRegistry的子类, 所以我们需要定位到 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);
    }
}

protected abstract void doRegister(URL url);

如上,我们重点关注 doRegister 方法调用即可,其他的代码先忽略。doRegister 方法是一个模板方法,因此我们到 FailbackRegistry 子类 ZookeeperRegistry 中进行分析。如下:


protected void doRegister(URL url) {
    try {
        // 通过 Zookeeper 客户端创建 临时/持久 节点,节点路径由 toUrlPath 方法生成,路径格式如下:
        //   /${group}/${serviceInterface}/providers/URL.encode(${url})
        // 比如
        //  /dubbo/com.czj.rpc.api.UserApi/providers/dubbo%3A%2F%2F192.168.241.15%3A20880%2Fcom.czj.rpc.api.UserApi%3Fanyhost%3Dtrue%26application%3Dhello-world-app%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dcom.czj.rpc.api.UserApi%26methods%3DgetName%2Cget%2Csave%26pid%3D7820%26side%3Dprovider%26timestamp%3D1578971448529
        zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
    } catch (Throwable e) {
        throw new RpcException("Failed to register...");
    }
}


如上,ZookeeperRegistry 在 doRegister 中调用了 Zookeeper 客户端创建服务节点。节点路径由 toUrlPath 方法生成,该方法逻辑不难理解,就不分析了。接下来分析 create 方法,如下:


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


上面方法先是通过递归创建当前节点的上一级路径,然后再根据 ephemeral 的值决定创建临时还是持久节点。createEphemeral 和 createPersistent 这两个方法都比较简单,这里简单分析其中的一个。如下:


public void createEphemeral(String path) {
    try {
        // 通过 Curator 框架创建节点
        client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
    } catch (NodeExistsException e) {
    } catch (Exception e) {
        throw new IllegalStateException(e.getMessage(), e);
    }
}


到此分析了dubbo的服务提供者如何 集成spring\对外提供服务\注册到远程中心

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值