zoukankan      html  css  js  c++  java
  • Dubbo-服务提供者启动流程

    参考:https://blog.csdn.net/prestigeding/article/details/80536385

    ServiceBean类结构图

    InitializingBean:其声明的接口为afterPropertiesSet方法,顾名思义,就是在bean初始化所有属性之后调用。
    DisposableBean:其声明的接口为destroy()方法,在Spring BeanFactory销毁一个单例实例之前调用。
    ApplicationContextAware:其声明的接口为void setApplicationContext(ApplicationContext applicationContext),实现了该接口,Spring容器在初始化Bean时会调用该方法,注入ApplicationContext:已方便该实例可以直接调用applicationContext获取其他Bean。
    ApplicationListener< ContextRefreshedEvent>:容器重新刷新时执行事件函数。
    BeanNameAware:其声明的接口为:void setBeanName(String name),实现该接口的Bean,其实例可以获取该实例在BeanFactory的id或name。
    FactoryBean:Spring初始化Bean的另外一种方式,例如dubbo:reference,需要返回的对象并不是ReferenceBean,而是要返回ref指定的代理类来执行业务操作,故这里使用FactoryBean非常合适,FactoryBean定义了如下三个方法:
      T getObject() throws Exception:获取需要返回的结果对象。
      Class<?> getObjectType():获取返回对象的类型。
      boolean isSingleton():返回是否是单例。  

    Spring事件监听

      DubboBootstrapApplicationListener接收Spring容器刷新完成事件

    public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
            implements Ordered {
    
        /**
         * The bean name of {@link DubboBootstrapApplicationListener}
         *
         * @since 2.7.6
         */
        public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
    
        private final DubboBootstrap dubboBootstrap;
    
        public DubboBootstrapApplicationListener() {
            this.dubboBootstrap = DubboBootstrap.getInstance();
        }
    
        @Override
        public void onApplicationContextEvent(ApplicationContextEvent event) {
            if (event instanceof ContextRefreshedEvent) {
                onContextRefreshedEvent((ContextRefreshedEvent) event);
            } else if (event instanceof ContextClosedEvent) {
                onContextClosedEvent((ContextClosedEvent) event);
            }
        }
    
        private void onContextRefreshedEvent(ContextRefreshedEvent event) {
            dubboBootstrap.start();
        }
    
        private void onContextClosedEvent(ContextClosedEvent event) {
            dubboBootstrap.stop();
        }
    
        @Override
        public int getOrder() {
            return LOWEST_PRECEDENCE;
        }
    }
    

      DubboBootstrap#start

    /**
     * Start the bootstrap
     */
    public DubboBootstrap start() {
    	if (started.compareAndSet(false, true)) {
    		ready.set(false);
    		// 读取配置信息
    		initialize();
    		if (logger.isInfoEnabled()) {
    			logger.info(NAME + " is starting...");
    		}
    		// 1. export Dubbo Services
    		// 发布Dubbo服务
    		exportServices();
    
    		// Not only provider register
    		if (!isOnlyRegisterProvider() || hasExportedServices()) {
    			// 2. export MetadataService
    			exportMetadataService();
    			//3. Register the local ServiceInstance if required
    			registerServiceInstance();
    		}
    
    		referServices();
    		if (asyncExportingFutures.size() > 0) {
    			new Thread(() -> {
    				try {
    					this.awaitFinish();
    				} catch (Exception e) {
    					logger.warn(NAME + " exportAsync occurred an exception.");
    				}
    				ready.set(true);
    				if (logger.isInfoEnabled()) {
    					logger.info(NAME + " is ready.");
    				}
    			}).start();
    		} else {
    			ready.set(true);
    			if (logger.isInfoEnabled()) {
    				logger.info(NAME + " is ready.");
    			}
    		}
    		if (logger.isInfoEnabled()) {
    			logger.info(NAME + " has started.");
    		}
    	}
    	return this;
    }
    
    private void exportServices() {
    	configManager.getServices().forEach(sc -> {
    		// TODO, compatible with ServiceConfig.export()
    		ServiceConfig serviceConfig = (ServiceConfig) sc;
    		serviceConfig.setBootstrap(this);
    
    		// 异步发布
    		if (exportAsync) {
    			ExecutorService executor = executorRepository.getServiceExporterExecutor();
    			Future<?> future = executor.submit(() -> {
    				sc.export();
    				exportedServices.add(sc);
    			});
    			asyncExportingFutures.add(future);
    		} 
    		// 同步发布
    		else {
    			sc.export();
    			exportedServices.add(sc);
    		}
    	});
    }
    

      ServiceConfig#export

    public synchronized void export() {
    	// 是否需要发布,由<dubbo:service export="true|false" />来指定
    	// 未指定由<dubbo:provider export="true|false" />来指定
    	if (!shouldExport()) {
    		return;
    	}
    
    	if (bootstrap == null) {
    		bootstrap = DubboBootstrap.getInstance();
    		bootstrap.initialize();
    	}
    
    	// 检查和更新子配置
    	checkAndUpdateSubConfigs();
    
    	//init serviceMetadata
    	serviceMetadata.setVersion(getVersion());
    	serviceMetadata.setGroup(getGroup());
    	serviceMetadata.setDefaultGroup(getGroup());
    	serviceMetadata.setServiceType(getInterfaceClass());
    	serviceMetadata.setServiceInterfaceName(getInterface());
    	serviceMetadata.setTarget(getRef());
    
    	// 延迟发布
    	if (shouldDelay()) {
    		// 创建并执行在给定延迟后启用的一次性操作
    		DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
    	} 
    	// 及时发布
    	else {
    		doExport();
    	}
    
    	exported();
    }
    

      ServiceConfig#checkAndUpdateSubConfigs

    private void checkAndUpdateSubConfigs() {
    	// 如果为<dubbo:service />|<dubbo:reference />设置了全局配置,
    	// 如<dubbo:provider />|<dubbo:consumer />,则缺省为全局配置
    	completeCompoundConfigs();
    	// 没有配置<dubbo:provider />,设置默认ProviderConfig对象
    	checkDefault();
    	// 没有配置<dubbo:protocol />,设置默认protocol,或者将protocolIds转化为ProtocolConfig对象
    	checkProtocol();
    	// SPI方式初始化一些配置(ReferenceConfig|ServiceConfig)
    	List<ConfigInitializer> configInitializers = ExtensionLoader.getExtensionLoader(ConfigInitializer.class)
    			.getActivateExtension(URL.valueOf("configInitializer://"), (String[]) null);
    	configInitializers.forEach(e -> e.initServiceConfig(this));
    
    	// if protocol is not injvm checkRegistry
    	// 如果protocol不仅仅是本地协议-injvm则设置默认注册配置或者将registryIds转化为RegistryConfig对象
    	// 校验注册信息的合法性,如address是否为空
    	if (!isOnlyInJvm()) {
    		checkRegistry();
    	}
    	// 刷新配置,一些未配置的信息使用默认配置
    	this.refresh();
    
    	if (StringUtils.isEmpty(interfaceName)) {
    		throw new IllegalStateException("<dubbo:service interface="" /> interface not allow null!");
    	}
    
    	// 泛型调用服务
    	if (ref instanceof GenericService) {
    		interfaceClass = GenericService.class;
    		if (StringUtils.isEmpty(generic)) {
    			generic = Boolean.TRUE.toString();
    		}
    	} 
    	// 普通调用服务
    	else {
    		try {
    			interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
    					.getContextClassLoader());
    		} catch (ClassNotFoundException e) {
    			throw new IllegalStateException(e.getMessage(), e);
    		}
    		// 校验接口和方法合法性
    		checkInterfaceAndMethods(interfaceClass, getMethods());
    		// 校验ref合法性
    		checkRef();
    		generic = Boolean.FALSE.toString();
    	}
    	if (local != null) {
    		if ("true".equals(local)) {
    			local = interfaceName + "Local";
    		}
    		Class<?> localClass;
    		try {
    			localClass = ClassUtils.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 = ClassUtils.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);
    		}
    	}
    	// 本地存根合法性校验,如是否有有参构造器
    	checkStubAndLocal(interfaceClass);
    	// 校验mock合法性,如mock类是否实现了interfaceClass
    	// false,不调用mock服务。
    	// true,当服务调用失败时,调用mock服务。
    	// default,当服务调用失败时,调用mock服务。
    	// force,强制调用mock服务(不管服务能否调用成功)。
    	ConfigValidationUtils.checkMock(interfaceClass, this);
    	// 校验配置参数值合法性
    	ConfigValidationUtils.validateServiceConfig(this);
    	// SPI方式配置信息校验成功后的后置处理
    	postProcessConfig();
    }
    

      ServiceConfig#doExportUrls

    private void doExportUrls() {
    	ServiceRepository repository = ApplicationModel.getServiceRepository();
    	// 注册服务描述映射接口全类名
    	ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());
    	// ProviderModel 表示服务提供者模型,此对象中存储了与服务提供者相关的信息。
    	// 比如服务的配置信息,服务实例等。每个被导出的服务对应一个 ProviderModel。
    	// ApplicationModel 持有所有的 ProviderModel。
    	repository.registerProvider(
    			getUniqueServiceName(),
    			ref,
    			serviceDescriptor,
    			this,
    			serviceMetadata
    	);
    
    	/**
    	 * 解析获得注册中心URL集合
    	 * 
    	 * 1.同类型注册中心
    	 * 		<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181;192.168.88.128:2181" />
    	 * 	解析获得两条数据:
    	 * 		registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=3060&qos.port=22226&registry=zookeeper&timestamp=1610074712005
    	 *		registry://192.168.88.128:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=3060&qos.port=22226&registry=zookeeper&timestamp=1610074712005
    	 * 2.同类型注册中心
    	 * 		<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181,192.168.88.128:2181" />
    	 * 	解析获得一条数据:
    	 * 		registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&backup=192.168.88.128:2181&dubbo=2.0.2&pid=10212&qos.port=22226&registry=zookeeper&timestamp=1610074806198
    	 * 3.不同类型注册中心
    	 * 		<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" />
    	 *		<dubbo:registry protocol="redis" address="127.0.0.1:8848" />
    	 * 	解析获得两条数据:
    	 * 		registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=10196&qos.port=22226&registry=zookeeper&timestamp=1610074944556
    	 *		registry://127.0.0.1:8848/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=10196&qos.port=22226&registry=redis&timestamp=1610074944567
    	 */
    	List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
    
    	for (ProtocolConfig protocolConfig : protocols) {
    		/**
    		 * 如果设置了contextpath参数,设置方式有两种:
    		 * 	<dubbo:protocol contextpath="demoProvider" name="dubbo" port="20881" />
    		 * 	<dubbo:provider contextpath="demoProvider" />
    		 * 未设置contextpath参数,pathKey=demoProviderGroup/org.apache.dubbo.demo.DemoService/v1.0
    		 * 设置了contextpath参数,pathKey=demoProviderGroup/demoProvider/org.apache.dubbo.demo.DemoService/v1.0
    		 */
    		String pathKey = URL.buildKey(getContextPath(protocolConfig)
    				.map(p -> p + "/" + path)
    				.orElse(path), group, version);
    		// 如果指定了路径,则再次注册服务描述映射路径,<pathKey, ServiceDescriptor>
    		repository.registerService(pathKey, interfaceClass);
    		serviceMetadata.setServiceKey(pathKey);
    		// 指定协议注册发布服务
    		doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    	}
    }
    

      ConfigValidationUtils#loadRegistries

    public static List<URL> loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) {
        // check && override if necessary
        List<URL> registryList = new ArrayList<URL>();
        ApplicationConfig application = interfaceConfig.getApplication();
        List<RegistryConfig> registries = interfaceConfig.getRegistries();
        if (CollectionUtils.isNotEmpty(registries)) {
            for (RegistryConfig config : registries) {
                String address = config.getAddress();
                if (StringUtils.isEmpty(address)) {
                    // 若 address 为空,则将其设为 0.0.0.0
                    address = ANYHOST_VALUE;
                }
                // 如果address不是N/A,说明服务需要远程注册到注册中心
                if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                    Map<String, String> map = new HashMap<String, String>();
                    // 将ApplicationConfig、RegistryConfig中的属性值添加到map中
                    AbstractConfig.appendParameters(map, application);
                    AbstractConfig.appendParameters(map, config);
                    // 添加 path、pid,protocol 等信息到 map 中
                    map.put(PATH_KEY, RegistryService.class.getName());
                    AbstractInterfaceConfig.appendRuntimeParameters(map);
                    if (!map.containsKey(PROTOCOL_KEY)) {
                        map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
                    }
                    /**
                     * 1. <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181;192.168.88.128:2181" />
                     *  解析获得两条数据:
                     *  zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=7220&qos.port=22226&timestamp=1610073722877
                     *  zookeeper://192.168.88.128:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=7220&qos.port=22226&timestamp=1610073722877
                     * 2. <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181,192.168.88.128:2181" />
                     *  解析获得一条数据:
                     *  zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&backup=192.168.88.128:2181&dubbo=2.0.2&pid=3164&qos.port=22226&timestamp=1610073611665
                     */
                    List<URL> urls = UrlUtils.parseURLs(address, map);
     
                    for (URL url : urls) {
                        url = URLBuilder.from(url)
                                // 添加&registry=zookeeper参数信息
                                .addParameter(REGISTRY_KEY, url.getProtocol())
                                // 将 URL协议头设置为 registry
                                // zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=3128&qos.port=22226&registry=zookeeper&timestamp=1610073611665
                                // registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=3128&qos.port=22226&registry=zookeeper&timestamp=1610073611665
                                .setProtocol(extractRegistryType(url))
                                .build();
                        // 通过判断条件,决定是否添加 url 到 registryList:
                        // 如果是服务提供者且配置了register=false,则忽略该地址
                        // 如果是服务消费者且配置了subscribe=false则忽略该地址
                        if ((provider && url.getParameter(REGISTER_KEY, true))
                                || (!provider && url.getParameter(SUBSCRIBE_KEY, true))) {
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }

      ServiceConfig#doExportUrlsFor1Protocol

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    	String name = protocolConfig.getName();
    	// 如果协议名为空,或空串,则将协议名变量设置为 dubbo
    	if (StringUtils.isEmpty(name)) {
    		name = DUBBO;
    	}
    
    	// 添加 side、版本、时间戳以及进程号等信息到 map 中
    	Map<String, String> map = new HashMap<String, String>();
    	map.put(SIDE_KEY, PROVIDER_SIDE);
    
    	// 添加dubbo版本号、timestamp、pid等信息到 map 中
    	ServiceConfig.appendRuntimeParameters(map);
    	// 通过反射将MetricsConfig、ApplicationConfig、ModuleConfig、ProviderConfig、
    	// ProtocolConfig、ServiceConfig中的属性值添加到map中
    	AbstractConfig.appendParameters(map, getMetrics());
    	AbstractConfig.appendParameters(map, getApplication());
    	AbstractConfig.appendParameters(map, getModule());
    	AbstractConfig.appendParameters(map, provider);
    	AbstractConfig.appendParameters(map, protocolConfig);
    	AbstractConfig.appendParameters(map, this);
    	MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
    	if (metadataReportConfig != null && metadataReportConfig.isValid()) {
    		map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);
    	}
    	// methods 为 MethodConfig 集合,MethodConfig 中存储了 <dubbo:method> 标签的配置信息
    	if (CollectionUtils.isNotEmpty(getMethods())) {
    		for (MethodConfig method : getMethods()) {
    			// 添加 MethodConfig 对象的字段信息到 map 中,键 = 方法名.属性名。
    			// 比如存储 <dubbo:method name="sayHello" retries="2"> 对应的 MethodConfig,
    			// 键 = sayHello.retries,map = {"sayHello.retries": 2, "xxx": "yyy"}
    			AbstractConfig.appendParameters(map, method, method.getName());
    			String retryKey = method.getName() + ".retry";
    			if (map.containsKey(retryKey)) {
    				String retryValue = map.remove(retryKey);
    				// 检测 MethodConfig retry 是否为 false,若是,则设置重试次数为0
    				if ("false".equals(retryValue)) {
    					map.put(method.getName() + ".retries", "0");
    				}
    			}
    			// 获取 ArgumentConfig 列表
    			List<ArgumentConfig> arguments = method.getArguments();
    			if (CollectionUtils.isNotEmpty(arguments)) {
    				for (ArgumentConfig argument : arguments) {
    					// convert argument type 检测 type 属性是否为空,或者空串(分支1 ⭐️)
    					if (argument.getType() != null && argument.getType().length() > 0) {
    						Method[] methods = interfaceClass.getMethods();
    						// visit all methods
    						if (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) {
    										// 检测 ArgumentConfig 中的 type 属性与方法参数列表
    										// 中的参数名称是否一致,不一致则抛出异常(分支2 ⭐️)
    										if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
    											// 添加 ArgumentConfig 字段信息到 map 中,
    											// 键前缀 = 方法名.index,比如:
    											// map = {"sayHello.3": true}
    											AbstractConfig.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 { // 分支3 ⭐️
    										// multiple callbacks in the method
    										for (int j = 0; j < argtypes.length; j++) {
    											Class<?> argclazz = argtypes[j];
    											// 从参数类型列表中查找类型名称为 argument.type 的参数
    											if (argclazz.getName().equals(argument.getType())) {
    												AbstractConfig.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());
    												}
    											}
    										}
    									}
    								}
    							}
    						}
    					// 用户未配置 type 属性,但配置了 index 属性,且 index != -1
    					} else if (argument.getIndex() != -1) { // 分支4 ⭐️
    						// 添加 ArgumentConfig 字段信息到 map 中 <dubbo:argument index='0' callback="true" />
    						AbstractConfig.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(GENERIC_KEY, generic);
    		map.put(METHODS_KEY, ANY_VALUE);
    	} else {
    		String revision = Version.getVersion(interfaceClass, version);
    		if (revision != null && revision.length() > 0) {
    			map.put(REVISION_KEY, revision);
    		}
    
    		// 为接口生成包裹类 Wrapper,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(METHODS_KEY, ANY_VALUE);
    		} else {
    			// 将逗号作为分隔符连接方法名,并将连接后的字符串放入 map 中
    			map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
    		}
    	}
    
    	// token配置方式有两种:
    	// 	<dubbo:service token="true" />
    	// 	<dubbo:provider token="true" />
    	if(ConfigUtils.isEmpty(token) && provider != null) {
    		token = provider.getToken();
    	}
    
    	// 添加 token 到 map 中
    	// 消费者提供了与提供者一致的token,才能访问提供者提供的服务
    	if (!ConfigUtils.isEmpty(token)) {
    		// 如果是true或者是default则使用UUID
    		if (ConfigUtils.isDefault(token)) {
    			map.put(TOKEN_KEY, UUID.randomUUID().toString());
    		} else {
    			map.put(TOKEN_KEY, token);
    		}
    	}
    	//init serviceMetadata attachments
    	serviceMetadata.getAttachments().putAll(map);
    
    	// 解析服务提供者的IP地址与端口
    	String host = findConfigedHosts(protocolConfig, registryURLs, map);
    	Integer port = findConfigedPorts(protocolConfig, name, map);
    	// 组装 URL,获取上下文路径
    	// dubbo://192.168.88.2:20881/demo-provider/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.88.2&bind.port=20881&deprecated=false&dispatcher=iDispatcher&dubbo=2.0.2&dynamic=true&executes=2&generic=false&interface=org.apache.dubbo.demo.DemoService&loadbalance=leastactive&methods=sayHello,sayHelloAsync&module=demo-module&pid=1368&qos.port=22226&release=&sayHello.retries=2&side=provider&threadpool=iThreadPool&timestamp=1610093664272
    	URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
    
    	// SPI方式自定义ConfiguratorFactory、Configurator对象添加额外的参数
    	if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
    			.hasExtension(url.getProtocol())) {
    		// 加载 ConfiguratorFactory,并生成 Configurator 实例,然后通过实例配置 url
    		url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
    				.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
    	}
    
    	/**
    	 * 一个服务可能既是Provider又是Consumer,因此就存在他自己调用自己服务的情况
    	 * 如果再通过网络去访问,那自然是舍近求远,因此他是有本地暴露服务的这个设计
    	 *
    	 * 本地暴露是暴露在JVM中,不需要网络通信
    	 * 远程暴露是将ip,端口等信息暴露给远程客户端,调用时需要网络通信
    	 */
    	String scope = url.getParameter(SCOPE_KEY);
    	// 如果配置为 none 不暴露服务,不向注册中心注册服务信息
    	// 不配置scope时,既暴露服务也考虑向注册中心注册服务信息
    	if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
    
    		// 当配置不是 remote 时则进行本地服务暴露 (当配置为 remote 时只进行远程服务暴露)
    		if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
    			// 本地(injvm)服务暴露,在本地JVM内存中创建存储Exporter对象
    			exportLocal(url);
    		}
    		// 当配置不是 local 时进行远程服务暴露 (当配置为 local 时只进行本地服务暴露)
    		if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
    			// 注册中心地址存在时,向注册中心注册服务信息
    			if (CollectionUtils.isNotEmpty(registryURLs)) {
    				for (URL registryURL : registryURLs) {
    					// 如果配置<dubbo:registry protocol="injvm" address="127.0.0.1:0" />时
    					// 只暴露本地服务,不向注册中心注册服务信息
    					if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
    						continue;
    					}
    					// 如果dubbo:service的dynamic属性未配置, 尝试取dubbo:registry的dynamic属性,
    					// 该属性的作用是否启用动态注册,如果设置为false,服务注册后,其状态显示为disable,
    					// 需要人工启用,当服务不可用时,也不会自动移除,同样需要人工处理,此属性不要在生产环境上配置。
    					url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
    					// 加载监视器链接
    					URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
    					if (monitorUrl != null) {
    						// 将监视器链接作为参数添加到 url 中
    						url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
    					}
    					if (logger.isInfoEnabled()) {
    						if (url.getParameter(REGISTER_KEY, true)) {
    							logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
    						} else {
    							logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
    						}
    					}
    
    					// 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);
    					}
    
    					// 为服务提供类(ref)生成 Invoker(dubbo的远程调用实现类)
    					Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
    					// DelegateProviderMetaDataInvoker 用于持有 Invoker 和 ServiceConfig
    					DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
    
    					// 导出服务,并生成 Exporter
    					// NettyServer监听IP为bind.ip(192.168.88.2),端口为bind.port(20881)
    					Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
    					exporters.add(exporter);
    				}
    			} 
    			// 当配置<dubbo:registry protocol="zookeeper" address="N/A" />时
    			// 不存在注册中心地址,仅暴露服务
    			else {
    				if (logger.isInfoEnabled()) {
    					logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
    				}
    				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
    			 */
    			WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter(METADATA_KEY, DEFAULT_METADATA_STORAGE_TYPE));
    			if (metadataService != null) {
    				metadataService.publishServiceDefinition(url);
    			}
    		}
    	}
    	this.urls.add(url);
    }
    

      RegistryProtocol#export

    /**
     * 1.调用 doLocalExport 暴露服务
     * 2.向注册中心注册服务,为了消费端获取可用服务
     * 3.向注册中心进行订阅,为了服务提供者URL发送变化后重新暴露服务
     * 4.创建并返回 DestroyableExporter
     */
    @Override
    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        // 获取注册中心 URL,以 zookeeper 注册中心为例:registry:// -> zookeeper://
        // zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.88.2%3A20881%2Fdemo-provider%2Forg.apache.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.88.2%26bind.port%3D20881%26deprecated%3Dfalse%26dispatcher%3DiDispatcher%26dubbo%3D2.0.2%26dynamic%3Dtrue%26executes%3D2%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.demo.DemoService%26loadbalance%3Dleastactive%26methods%3DsayHello%2CsayHelloAsync%26module%3Ddemo-module%26monitor%3Ddubbo%253A%252F%252F127.0.0.1%253A2181%252Forg.apache.dubbo.registry.RegistryService%253Fapplication%253Ddemo-provider%2526dubbo%253D2.0.2%2526pid%253D1444%2526protocol%253Dregistry%2526qos.port%253D22226%2526refer%253Dapplication%25253Ddemo-provider%252526dubbo%25253D2.0.2%252526interface%25253Dorg.apache.dubbo.monitor.MonitorService%252526interval%25253D100%252526pid%25253D1444%252526qos.port%25253D22226%252526register.ip%25253D192.168.88.2%252526timestamp%25253D1610333468481%2526registry%253Dzookeeper%2526timestamp%253D1610333468168%26pid%3D1444%26qos.port%3D22226%26release%3D%26sayHello.retries%3D2%26side%3Dprovider%26threadpool%3DiThreadPool%26timestamp%3D1610333468176&pid=1444&qos.port=22226&timestamp=1610333468168
        URL registryUrl = getRegistryUrl(originInvoker);
        // 获取URL的export属性值即服务提供者的URL
        // dubbo://192.168.88.2:20881/demo-provider/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.88.2&bind.port=20881&deprecated=false&dispatcher=iDispatcher&dubbo=2.0.2&dynamic=true&executes=2&generic=false&interface=org.apache.dubbo.demo.DemoService&loadbalance=leastactive&methods=sayHello,sayHelloAsync&module=demo-module&monitor=dubbo%3A%2F%2F127.0.0.1%3A2181%2Forg.apache.dubbo.registry.RegistryService%3Fapplication%3Ddemo-provider%26dubbo%3D2.0.2%26pid%3D1444%26protocol%3Dregistry%26qos.port%3D22226%26refer%3Dapplication%253Ddemo-provider%2526dubbo%253D2.0.2%2526interface%253Dorg.apache.dubbo.monitor.MonitorService%2526interval%253D100%2526pid%253D1444%2526qos.port%253D22226%2526register.ip%253D192.168.88.2%2526timestamp%253D1610333468481%26registry%3Dzookeeper%26timestamp%3D1610333468168&pid=1444&qos.port=22226&release=&sayHello.retries=2&side=provider&threadpool=iThreadPool&timestamp=1610333468176
        URL providerUrl = getProviderUrl(originInvoker);
     
        // 获取订阅 URL,服务提供者向注册中心订阅自己,主要是为了服务提供者URL发送变化后重新暴露服务,当然会将dubbo:reference的check属性设置为false
        // provider://192.168.88.2:20881/demo-provider/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.88.2&bind.port=20881&category=configurators&check=false&deprecated=false&dispatcher=iDispatcher&dubbo=2.0.2&dynamic=true&executes=2&generic=false&interface=org.apache.dubbo.demo.DemoService&loadbalance=leastactive&methods=sayHello,sayHelloAsync&module=demo-module&monitor=dubbo%3A%2F%2F127.0.0.1%3A2181%2Forg.apache.dubbo.registry.RegistryService%3Fapplication%3Ddemo-provider%26dubbo%3D2.0.2%26pid%3D1444%26protocol%3Dregistry%26qos.port%3D22226%26refer%3Dapplication%253Ddemo-provider%2526dubbo%253D2.0.2%2526interface%253Dorg.apache.dubbo.monitor.MonitorService%2526interval%253D100%2526pid%253D1444%2526qos.port%253D22226%2526register.ip%253D192.168.88.2%2526timestamp%253D1610333468481%26registry%3Dzookeeper%26timestamp%3D1610333468168&pid=1444&qos.port=22226&release=&sayHello.retries=2&side=provider&threadpool=iThreadPool&timestamp=1610333468176
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
        // 创建监听器,当配置中心数据发生变化时进行监听处理
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
     
        // 根据外部配置刷新本地配置(如果外部配置和本地配置信息不一致的话)
        providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
        // 暴露远程服务并加缓存,根据各自协议,服务提供者建立网络服务器在特定端口建立监听,监听来自消息消费端服务的请求
        // 以dubbo协议为例,创建NettyServer监听指定IP和端口
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
     
        // 根据注册中心URL,从注册中心工厂中获取指定的注册中心实现类:zookeeper注册中心的实现类为:ZookeeperRegistry
        // ZookeeperRegistry的构造器中连接注册中心
        final Registry registry = getRegistry(originInvoker);
        // 获取服务提供者URL中的register属性
        // 如果为true则调用注册中心的ZookeeperRegistry#register方法向注册中心注册服务(实际由其父类FailbackRegistry实现)
        final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
     
        // 根据 register 属性的值决定是否注册服务,默认为true
        boolean register = providerUrl.getParameter(REGISTER_KEY, true);
        if (register) {
            // 向注册中心注册服务
            // 以zookeeper为例将服务信息存储到相应目录中
            register(registryUrl, registeredProviderUrl);
        }
     
        // register stated url on provider model
        registerStatedUrl(registryUrl, registeredProviderUrl, register);
     
        exporter.setRegisterUrl(registeredProviderUrl);
        exporter.setSubscribeUrl(overrideSubscribeUrl);
     
        // 服务提供端向注册中心进行订阅,即将弃用,这种方式使用于2.6.x版本或更早版本
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
     
        // 服务注册暴露成功后进行通知
        notifyExport(exporter);
        // 创建并返回 DestroyableExporter
        return new DestroyableExporter<>(exporter);
    }

      RegistryProtocol#doLocalExport

    @SuppressWarnings("unchecked")
    private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
    	String key = getCacheKey(originInvoker);
    	// 访问缓存,不存在则写缓存
    	return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
    		// 创建 Invoker 委托类对象
    		// providerUrl=dubbo://192.168.88.2:20881/demo-provider/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.88.2&bind.port=20881&deprecated=false&dispatcher=iDispatcher&dubbo=2.0.2&dynamic=true&executes=2&generic=false&interface=org.apache.dubbo.demo.DemoService&loadbalance=leastactive&methods=sayHello,sayHelloAsync&module=demo-module&monitor=dubbo%3A%2F%2F127.0.0.1%3A2181%2Forg.apache.dubbo.registry.RegistryService%3Fapplication%3Ddemo-provider%26dubbo%3D2.0.2%26pid%3D1444%26protocol%3Dregistry%26qos.port%3D22226%26refer%3Dapplication%253Ddemo-provider%2526dubbo%253D2.0.2%2526interface%253Dorg.apache.dubbo.monitor.MonitorService%2526interval%253D100%2526pid%253D1444%2526qos.port%253D22226%2526register.ip%253D192.168.88.2%2526timestamp%253D1610333468481%26registry%3Dzookeeper%26timestamp%3D1610333468168&pid=1444&qos.port=22226&release=&sayHello.retries=2&side=provider&threadpool=iThreadPool&timestamp=1610333468176
    		Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
    		// 根据Dubbo内置的SPI机制,将调用DubboProtocol#export方法
    		return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
    	});
    }
    

      DubboProtocol#export

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    	// dubbo://192.168.88.2:20881/demo-provider/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.88.2&bind.port=20881&deprecated=false&dispatcher=iDispatcher&dubbo=2.0.2&dynamic=true&executes=2&generic=false&interface=org.apache.dubbo.demo.DemoService&loadbalance=leastactive&methods=sayHello,sayHelloAsync&module=demo-module&monitor=dubbo%3A%2F%2F127.0.0.1%3A2181%2Forg.apache.dubbo.registry.RegistryService%3Fapplication%3Ddemo-provider%26dubbo%3D2.0.2%26pid%3D11080%26protocol%3Dregistry%26qos.port%3D22226%26refer%3Dapplication%253Ddemo-provider%2526dubbo%253D2.0.2%2526interface%253Dorg.apache.dubbo.monitor.MonitorService%2526interval%253D100%2526pid%253D11080%2526qos.port%253D22226%2526register.ip%253D192.168.88.2%2526timestamp%253D1610336987787%26registry%3Dzookeeper%26timestamp%3D1610336987412&pid=11080&qos.port=22226&release=&sayHello.retries=2&side=provider&threadpool=iThreadPool&timestamp=1610336987422
    	URL url = invoker.getUrl();
    
    	// 获取服务标识,理解成服务坐标也行。由服务组名,服务名,服务版本号以及端口组成。比如:
    	// demoGroup/org.apache.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."));
    			}
    
    		}
    	}
    
    	// 启动服务器
    	openServer(url);
    	// 优化序列化
    	optimizeSerialization(url);
    
    	return exporter;
    }
    

      DubboProtocol#openServer

    private void openServer(URL url) {
    	// 获取 host:port,并将其作为服务器实例的 key,用于标识当前的服务器实例
    	String key = url.getAddress();
    	// 服务消费端可以暴露仅供服务提供端调用的服务
    	boolean isServer = url.getParameter(IS_SERVER_KEY, true);
    	if (isServer) {
    		ProtocolServer server = serverMap.get(key);
    		if (server == null) {
    			synchronized (this) {
    				server = serverMap.get(key);
    				if (server == null) {
    					// 创建服务器实例
    					serverMap.put(key, createServer(url));
    				}
    			}
    		} else {
    			// 如果服务器已经存在,用当前URL重置服务器
    			// 因为一个dubbo应用服务中会有多个<dubbo:service />标签
    			// 这些标签都会在服务提供者的同一个IP地址、端口号上暴露服务
    			server.reset(url);
    		}
    	}
    }
    

      DubboProtocol#createServer

    /**
     * 1.检测是否存在 server 参数所代表的 Transporter 拓展
     * 2.创建服务器实例
     * 3.检测是否支持 client 参数所表示的 Transporter 拓展,不存在也是抛出异常
     */
    private ProtocolServer createServer(URL url) {
    	url = URLBuilder.from(url)
    			// 为服务提供者url增加channel.readonly.sent属性默认为true,表示在发送请求时是否等待将字节写入socket后再返回
    			.addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
    			// 为服务提供者url增加heartbeat属性,表示心跳间隔时间,默认为60*1000,表示60s
    			.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
    			// 为服务提供者url增加codec属性,默认值为dubbo,协议编码方式
    			.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 {
    		// 根据服务提供者URL,ExchangeHandler构建ExchangeServer实例
    		server = Exchangers.bind(url, requestHandler);
    	} catch (RemotingException e) {
    		throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    	}
    
    	// 获取 client 参数,可指定 netty,mina
    	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 new DubboProtocolServer(server);
    }
    

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

      HeaderExchanger#bind

    @Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    	// 创建 HeaderExchangeServer 实例,该方法包含了多个逻辑,分别如下:
    	//   1. new HeaderExchangeHandler(handler)
    	//	 2. new DecodeHandler(new HeaderExchangeHandler(handler))
    	//   3. Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))
    	// 	 4. new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))))
    	return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }
    

      Transporters#bind

    public static RemotingServer 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 实例,并调用bind方法
    	return getTransporter().bind(url, handler);
    }
    

      Transporter继承结构图

       以NettyTransporter为例,NettyTransporter#bind

    @Override
    public RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException {
    	// 创建 NettyServer
    	return new NettyServer(url, handler);
    }
    

      NettyServer#doOpen

    @Override
    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(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
    	// 创建 ServerBootstrap
    	bootstrap = new ServerBootstrap(channelFactory);
    
    	final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
    	channels = nettyHandler.getChannels();
    	// https://issues.jboss.org/browse/NETTY-365
    	// https://issues.jboss.org/browse/NETTY-379
    	// final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
    	bootstrap.setOption("child.tcpNoDelay", true);
    	bootstrap.setOption("backlog", getUrl().getPositiveParameter(BACKLOG_KEY, Constants.DEFAULT_BACKLOG));
    	// 设置 PipelineFactory
    	bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
    		@Override
    		public ChannelPipeline getPipeline() {
    			NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
    			ChannelPipeline pipeline = Channels.pipeline();
    			/*int idleTimeout = getIdleTimeout();
    			if (idleTimeout > 10000) {
    				pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));
    			}*/
    			pipeline.addLast("decoder", adapter.getDecoder());
    			pipeline.addLast("encoder", adapter.getEncoder());
    			pipeline.addLast("handler", nettyHandler);
    			return pipeline;
    		}
    	});
    	// bind 绑定到指定的 ip 和端口上
    	channel = bootstrap.bind(getBindAddress());
    }
    

      从DubboProtocol#openServer中可以看出,解析第一个<dubbo:service/>标签时会调用DubboProtocol#createServer方法,在解析后续的<dubbo:service/>标签时并不会调用DubboProtocol#createServer方法,而是会调用DubboProtocolServer#reset方法即调用NettyServer#reset方法

      AbstractServer#reset

    @Override
    public void reset(URL url) {
    	if (url == null) {
    		return;
    	}
    	try {
    		if (url.hasParameter(ACCEPTS_KEY)) {
    			int a = url.getParameter(ACCEPTS_KEY, 0);
    			if (a > 0) {
    				this.accepts = a;
    			}
    		}
    	} catch (Throwable t) {
    		logger.error(t.getMessage(), t);
    	}
    	try {
    		if (url.hasParameter(IDLE_TIMEOUT_KEY)) {
    			int t = url.getParameter(IDLE_TIMEOUT_KEY, 0);
    			if (t > 0) {
    				this.idleTimeout = t;
    			}
    		}
    	} catch (Throwable t) {
    		logger.error(t.getMessage(), t);
    	}
    	// 调整线程池的相关线程数量?
    	// 多个<dubbo:service />标签对应一个executor,线程池core数量和max数量怎么确定?
    	executorRepository.updateThreadpool(url, executor);
    	// 覆盖原先NettyServer的volatile URL url的属性,NettyHandler上加了注解@Sharable?
    	super.setUrl(getUrl().addParameters(url.getParameters()));
    }
    

      

  • 相关阅读:
    vue element-admin 清空校验
    vue+elementui 动态改变表单必填项
    什么是中台
    项目中遇到的一道算法题
    【解决】Word中公式突然乱码
    【解决】MATLAB报错:此上下文中不支持函数定义,请在代码文件中创建函数。
    【解决】Word打印成PDF出错:%%[ ProductName: Distiller ]%%
    Bike Sharing Analysis(二)- 假设检验方法
    Bike Sharing Analysis(一)- 探索数据
    Spark Structured Streaming(二)实战
  • 原文地址:https://www.cnblogs.com/BINGJJFLY/p/14242446.html
Copyright © 2011-2022 走看看