1. 概述

Dubbo 的配置目前提供了四种配置方式:1. API 配置 2. 属性配置 3. XML 配置 4. 注解配置

2. 配置一览

我们来看看 dubbo-config-api 的项目结构,如下图所示:


类之间的关系如图所示:

3. Config

我们现在按照配置之间的关系,逐步分析

3.1 AbstractConfig

com.alibaba.dubbo.config.AbstractConfig ,抽象配置类,除了 ArgumentConfig ,我们可以看到所有的配置类都继承该类。

AbstractConfig 主要提供配置解析与校验相关的工具方法。
appendParameters(parameters, config, prefix) 方法,将配置对象的属性,添加到参数集合。

 /*** 将配置对象的属性,添加到参数集合** @param parameters 参数集合* @param config 配置对象* @param prefix 属性前缀*/@SuppressWarnings("unchecked")protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) {if (config == null) {return;}//获得所有方法的数组,为下面通过反射获得配置项的值做准备。Method[] methods = config.getClass().getMethods();//循环每个方法for (Method method : methods) {try {String name = method.getName();//方法为获得基本类型 + public 的 getting 方法if ((name.startsWith("get") || name.startsWith("is"))&& !"getClass".equals(name)&& Modifier.isPublic(method.getModifiers())&& method.getParameterTypes().length == 0&& isPrimitive(method.getReturnType())) { // 方法为获取基本类型,public 的 getting 方法。Parameter parameter = method.getAnnotation(Parameter.class);//返回值类型为 Object 或排除( `@Parameter.exclue=true` )的配置项,跳过if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {continue;}// 获得属性名int i = name.startsWith("get") ? 3 : 2;String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");String key;if (parameter != null && parameter.key() != null && parameter.key().length() > 0) {key = parameter.key();} else {key = prop;}// 获得属性值Object value = method.invoke(config, new Object[0]);String str = String.valueOf(value).trim();if (value != null && str.length() > 0) {// 转义if (parameter != null && parameter.escaped()) {str = URL.encode(str);}// 拼接,详细说明参见 `Parameter#append()` 方法的说明。if (parameter != null && parameter.append()) {String pre = parameters.get(Constants.DEFAULT_KEY + "." + key); // default. 里获取,适用于 ServiceConfig =》ProviderConfig 、ReferenceConfig =》ConsumerConfig 。if (pre != null && pre.length() > 0) {str = pre + "," + str;}pre = parameters.get(key); // 通过 `parameters` 属性配置,例如 `AbstractMethodConfig.parameters` 。if (pre != null && pre.length() > 0) {str = pre + "," + str;}}if (prefix != null && prefix.length() > 0) {key = prefix + "." + key;}//添加配置项到 parametersparameters.put(key, str);//当 `@Parameter.required = true` 时,校验配置项非空} else if (parameter != null && parameter.required()) {throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null");}} else if ("getParameters".equals(name)&& Modifier.isPublic(method.getModifiers())&& method.getParameterTypes().length == 0&& method.getReturnType() == Map.class) { // `#getParameters()` 方法//通过反射,获得 #getParameters() 的返回值为 map  Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]);if (map != null && map.size() > 0) {String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");for (Map.Entry<String, String> entry : map.entrySet()) {//将 map 添加到 parameters ,kv 格式为 prefix:entry.key entry.value 。parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());}}}} catch (Exception e) {throw new IllegalStateException(e.getMessage(), e);}}}

#appendProperties(config) 方法,读取环境变量和 properties 配置到配置对象。在 精尽 Dubbo 源码分析 —— 属性配置详细解析。

3.2 ModuleConfig

模块信息配置


具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:module》 文档。

3.3 RegistryConfig

注册中心配置。
具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:registry》 文档。

3.4 ApplicationConfig

应用配置。
具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:application》 文档。

3.5 MonitorConfig

监控中心配置。
具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:monitor》 文档。

3.6 ArgumentConfig

方法参数配置
具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:argument》 文档。

3.7 ProtocolConfig

服务提供者协议配置

具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:protocol》 文档。

3.8 AbstractMethodConfig

具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:method》 文档。

3.9 MethodConfig

继承 AbstractMethodConfig ,方法级配置。

具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:method》 文档。

3.10 AbstractInterfaceConfig

继承 AbstractMethodConfig ,抽象接口配置类
具体属性的解释,参见 《Dubbo 用户指南 —— dubbo: reference》 文档和 《Dubbo 用户指南 —— dubbo: reference》 文档

3.11 AbstractServiceConfig

实现 AbstractInterfaceConfig ,抽象服务配置类
具体属性的解释,参见 《Dubbo 用户指南 —— dubbo: provider》 文档和 《Dubbo 用户指南 —— dubbo: reference》 文档

3.12 ProviderConfig

实现 AbstractServiceConfig ,服务提供者缺省值配置。

具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:provider》 文档。

3.13 ServiceConfig

服务提供者暴露服务配置类。
export 方法,暴露服务。方法作用:1.进一步初始化 ServiceConfig 对象。2.校验 ServiceConfig 对象的配置项。
3.使用 ServiceConfig 对象,生成 Dubbo URL 对象数组。4.使用 Dubbo URL 对象,暴露服务。

/*** 暴露服务*/public synchronized void export() {// 当 export 或者 delay 未配置,从 ProviderConfig 对象读取。if (provider != null) {if (export == null) {export = provider.getExport();}if (delay == null) {delay = provider.getDelay();}}// 不暴露服务( export = false ) ,则不进行暴露服务逻辑。if (export != null && !export) {return;}// 延迟暴露if (delay != null && delay > 0) {//当配置延迟暴露( delay > 0 )时,使用 delayExportExecutor 延迟调度,调用 #doExport() 方法delayExportExecutor.schedule(new Runnable() {public void run() {doExport();}}, delay, TimeUnit.MILLISECONDS);// 立即暴露} else {doExport();}}

doExport() 方法,代码如下:

/*** 执行暴露服务*/protected synchronized void doExport() {// 检查是否可以暴露,若可以,标记已经暴露。if (unexported) {throw new IllegalStateException("Already unexported!");}if (exported) {return;}//检查是否可以暴露。若可以,标记已经暴露( exported = true )exported = true;// 校验接口名非空if (interfaceName == null || interfaceName.length() == 0) {throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");}// 拼接属性配置(环境变量 + properties 属性)到 ProviderConfig 对象checkDefault();// 从 ProviderConfig 对象中,读取 application、module、registries、monitor、protocols 配置对象。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();}}// 从 ModuleConfig 对象中,读取 registries、monitor 配置对象。if (module != null) {if (registries == null) {registries = module.getRegistries();}if (monitor == null) {monitor = module.getMonitor();}}// 从 ApplicationConfig 对象中,读取 registries、monitor 配置对象。if (application != null) {if (registries == null) {registries = application.getRegistries();}if (monitor == null) {monitor = application.getMonitor();}}// 泛化接口的实现if (ref instanceof GenericService) {interfaceClass = GenericService.class;if (StringUtils.isEmpty(generic)) {generic = Boolean.TRUE.toString();}// 普通接口的实现} else {try {#doExportUrls() 方//根据 interfaceName ,获得对应的接口类,并赋值给 interfaceClassinterfaceClass = Class.forName(interfaceName, true, Thread.currentThread().getContextClassLoader());} catch (ClassNotFoundException e) {throw new IllegalStateException(e.getMessage(), e);}// 校验接口和方法checkInterfaceAndMethods(interfaceClass, methods);// 校验指向的 service 对象checkRef();generic = Boolean.FALSE.toString();}// 处理服务接口客户端本地代理( `local` )相关。实际目前已经废弃,使用 `stub` 属性,参见 `AbstractInterfaceConfig#setLocal` 方法。if (local != null) {// 设为 true,表示使用缺省代理类名,即:接口名 + Local 后缀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);}}// 处理服务接口客户端本地代理( `stub` )相关if (stub != null) {// 设为 true,表示使用缺省代理类名,即:接口名 + Stub 后缀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();// 校验 RegistryConfig 配置。checkRegistry();// 校验 ProtocolConfig 配置数组。checkProtocol();// 读取环境变量和 properties 配置到 ServiceConfig 对象。appendProperties(this);// 校验 Stub 和 Mock 相关的配置checkStubAndMock(interfaceClass);// 服务路径,缺省为接口名if (path == null || path.length() == 0) {path = interfaceName;}// 暴露服务doExportUrls();ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);}

doExportUrls() 方法中,调用 #doExportUrlsFor1Protocol(protocolConfig, registryURLs) 方法,代码如下:

/*** 基于单个协议,暴露服务** @param protocolConfig 协议配置对象* @param registryURLs 注册中心链接对象数组*/private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {// 协议名String name = protocolConfig.getName();if (name == null || name.length() == 0) {name = "dubbo";}// 将 `side`,`dubbo`,`timestamp`,`pid` 参数,添加到 `map` 集合中。Map<String, String> map = new HashMap<String, String>();map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));if (ConfigUtils.getPid() > 0) {map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));}// 将各种配置对象,添加到 `map` 集合中。appendParameters(map, application);appendParameters(map, module);appendParameters(map, provider, Constants.DEFAULT_KEY); // ProviderConfig ,为 ServiceConfig 的默认属性,因此添加 `default` 属性前缀。appendParameters(map, protocolConfig);appendParameters(map, this);// 将 MethodConfig 对象数组,添加到 `map` 集合中。if (methods != null && !methods.isEmpty()) {for (MethodConfig method : methods) {// 将 MethodConfig 对象,添加到 `map` 集合中。appendParameters(map, method, method.getName());// 当 配置了 `MethodConfig.retry = false` 时,强制禁用重试String retryKey = method.getName() + ".retry";if (map.containsKey(retryKey)) {String retryValue = map.remove(retryKey);if ("false".equals(retryValue)) {map.put(method.getName() + ".retries", "0");}}// 将 ArgumentConfig 对象数组,添加到 `map` 集合中。List<ArgumentConfig> arguments = method.getArguments();if (arguments != null && !arguments.isEmpty()) {for (ArgumentConfig argument : arguments) {// convert argument typeif (argument.getType() != null && argument.getType().length() > 0) { // 指定了类型Method[] methods = interfaceClass.getMethods();// visit all methodsif (methods != null && methods.length > 0) {for (int i = 0; i < methods.length; i++) {String methodName = methods[i].getName();// target the method, and get its signatureif (methodName.equals(method.getName())) { // 找到指定方法Class<?>[] argTypes = methods[i].getParameterTypes();// one callback in the methodif (argument.getIndex() != -1) { // 指定单个参数的位置 + 类型if (argTypes[argument.getIndex()].getName().equals(argument.getType())) {// 将 ArgumentConfig 对象,添加到 `map` 集合中。appendParameters(map, argument, method.getName() + "." + argument.getIndex()); // `${methodName}.${index}`} 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 methodfor (int j = 0; j < argTypes.length; j++) {Class<?> argClazz = argTypes[j];if (argClazz.getName().equals(argument.getType())) {// 将 ArgumentConfig 对象,添加到 `map` 集合中。appendParameters(map, argument, method.getName() + "." + j); // `${methodName}.${index}`if (argument.getIndex() != -1 && argument.getIndex() != j) { // 多余的判断,因为 `argument.getIndex() == -1` 。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) { // 指定单个参数的位置// 将 ArgumentConfig 对象,添加到 `map` 集合中。appendParameters(map, argument, method.getName() + "." + argument.getIndex()); // `${methodName}.${index}`} 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、methods、revisionif (ProtocolUtils.isGeneric(generic)) {map.put("generic", generic);map.put("methods", Constants.ANY_VALUE);} else {String revision = Version.getVersion(interfaceClass, version);if (revision != null && revision.length() > 0) {map.put("revision", revision); // 修订本}String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); // 获得方法数组if (methods.length == 0) {logger.warn("NO method found in service interface " + interfaceClass.getName());map.put("methods", Constants.ANY_VALUE);} else {map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));}}// token ,参见《令牌校验》https://dubbo.gitbooks.io/dubbo-user-book/demos/token-authorization.htmlif (!ConfigUtils.isEmpty(token)) {if (ConfigUtils.isDefault(token)) { // true || default 时,UUID 随机生成map.put("token", UUID.randomUUID().toString());} else {map.put("token", token);}}// 协议为 injvm 时,不注册,不通知。if ("injvm".equals(protocolConfig.getName())) {protocolConfig.setRegister(false);map.put("notify", "false");}// export serviceString contextPath = protocolConfig.getContextpath();if ((contextPath == null || contextPath.length() == 0) && provider != null) {contextPath = provider.getContextpath();}// host、portString host = this.findConfigedHosts(protocolConfig, registryURLs, map);Integer port = this.findConfigedPorts(protocolConfig, name, map);// 创建 Dubbo URL 对象URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);// 配置规则,参见《配置规则》https://dubbo.gitbooks.io/dubbo-user-book/demos/config-rule.html// TODO 8038 ServiceConfig 为啥判断了 url.protocolif (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol()).getConfigurator(url).configure(url);}

3.14 AbstractReferenceConfig

实现 AbstractInterfaceConfig ,抽象引用配置类。

具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:reference》 文档和《Dubbo 用户指南 —— dubbo:consumer》

3.15 ConsumerConfig

实现 AbstractReferenceConfig ,服务消费者缺省值配置。

具体属性的解释,参见 《Dubbo 用户指南 —— dubbo:consumer》。

3.16 ReferenceConfig

服务消费者引用服务配置类。

get 方法,获取服务配置

 public synchronized T get() {// 已销毁,不可获得if (destroyed) {throw new IllegalStateException("Already destroyed!");}// 初始化if (ref == null) {init();}return ref;}

init 方法,进行初始化

private void init() {// 已经初始化,直接返回if (initialized) {return;}initialized = true;// 校验接口名非空if (interfaceName == null || interfaceName.length() == 0) {throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");}// 拼接属性配置(环境变量 + properties 属性)到 ConsumerConfig 对象// get consumer's global configurationcheckDefault();// 拼接属性配置(环境变量 + properties 属性)到 ReferenceConfig 对象appendProperties(this);// 若未设置 `generic` 属性,使用 `ConsumerConfig.generic` 属性。if (getGeneric() == null && getConsumer() != null) {setGeneric(getConsumer().getGeneric());}// 泛化接口的实现if (ProtocolUtils.isGeneric(getGeneric())) {interfaceClass = GenericService.class;// 普通接口的实现} else {try {interfaceClass = Class.forName(interfaceName, true, Thread.currentThread().getContextClassLoader());} catch (ClassNotFoundException e) {throw new IllegalStateException(e.getMessage(), e);}// 校验接口和方法checkInterfaceAndMethods(interfaceClass, methods);}// 直连提供者,参见文档《直连提供者》https://dubbo.gitbooks.io/dubbo-user-book/demos/explicit-target.html// 【直连提供者】第一优先级,通过 -D 参数指定 ,例如 java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890String resolve = System.getProperty(interfaceName);String resolveFile = null;// 【直连提供者】第二优先级,通过文件映射,例如 com.alibaba.xxx.XxxService=dubbo://localhost:20890if (resolve == null || resolve.length() == 0) {// 默认先加载,`${user.home}/dubbo-resolve.properties` 文件 ,无需配置resolveFile = System.getProperty("dubbo.resolve.file");if (resolveFile == null || resolveFile.length() == 0) {File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");if (userResolveFile.exists()) {resolveFile = userResolveFile.getAbsolutePath();}}// 存在 resolveFile ,则进行文件读取加载。if (resolveFile != null && resolveFile.length() > 0) {Properties properties = new Properties();FileInputStream fis = null;try {fis = new FileInputStream(new File(resolveFile));properties.load(fis);} catch (IOException e) {throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e);} finally {try {if (null != fis) fis.close();} catch (IOException e) {logger.warn(e.getMessage(), e);}}resolve = properties.getProperty(interfaceName);}}// 设置直连提供者的 urlif (resolve != null && resolve.length() > 0) {url = resolve;if (logger.isWarnEnabled()) {if (resolveFile != null && resolveFile.length() > 0) {logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");} else {logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");}}}// 从 ConsumerConfig 对象中,读取 application、module、registries、monitor 配置对象。if (consumer != null) {if (application == null) {application = consumer.getApplication();}if (module == null) {module = consumer.getModule();}if (registries == null) {registries = consumer.getRegistries();}if (monitor == null) {monitor = consumer.getMonitor();}}// 从 ModuleConfig 对象中,读取 registries、monitor 配置对象。if (module != null) {if (registries == null) {registries = module.getRegistries();}if (monitor == null) {monitor = module.getMonitor();}}// 从 ApplicationConfig 对象中,读取 registries、monitor 配置对象。if (application != null) {if (registries == null) {registries = application.getRegistries();}if (monitor == null) {monitor = application.getMonitor();}}// 校验 ApplicationConfig 配置。checkApplication();// 校验 Stub 和 Mock 相关的配置checkStubAndMock(interfaceClass);// 将 `side`,`dubbo`,`timestamp`,`pid` 参数,添加到 `map` 集合中。Map<String, String> map = new HashMap<String, String>();Map<Object, Object> attributes = new HashMap<Object, Object>();map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));if (ConfigUtils.getPid() > 0) {map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));}// methods、revision、interfaceif (!isGeneric()) {String revision = Version.getVersion(interfaceClass, version);if (revision != null && revision.length() > 0) {map.put("revision", revision);}String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); // 获得方法数组if (methods.length == 0) {logger.warn("NO method found in service interface " + interfaceClass.getName());map.put("methods", Constants.ANY_VALUE);} else {map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));}}map.put(Constants.INTERFACE_KEY, interfaceName);// 将各种配置对象,添加到 `map` 集合中。appendParameters(map, application);appendParameters(map, module);appendParameters(map, consumer, Constants.DEFAULT_KEY);appendParameters(map, this);// 获得服务键,作为前缀String prefix = StringUtils.getServiceKey(map);// 将 MethodConfig 对象数组,添加到 `map` 集合中。if (methods != null && !methods.isEmpty()) {for (MethodConfig method : methods) {// 将 MethodConfig 对象,添加到 `map` 集合中。appendParameters(map, method, method.getName());// 当 配置了 `MethodConfig.retry = false` 时,强制禁用重试String retryKey = method.getName() + ".retry";if (map.containsKey(retryKey)) {String retryValue = map.remove(retryKey);if ("false".equals(retryValue)) {map.put(method.getName() + ".retries", "0");}}// 将带有 @Parameter(attribute = true) 配置对象的属性,添加到参数集合。参见《事件通知》http://dubbo.io/books/dubbo-user-book/demos/events-notify.htmlappendAttributes(attributes, method, prefix + "." + method.getName());// 检查属性集合中的事件通知方法是否正确。若正确,进行转换。checkAndConvertImplicitConfig(method, map, attributes);}}// 以系统环境变量( DUBBO_IP_TO_REGISTRY ) 作为服务注册地址,参见 https://github.com/dubbo/dubbo-docker-sample 项目。String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY);if (hostToRegistry == null || hostToRegistry.length() == 0) {hostToRegistry = NetUtils.getLocalHost();} else if (isInvalidLocalHost(hostToRegistry)) {throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);}map.put(Constants.REGISTER_IP_KEY, hostToRegistry);
// 省略【引用服务】

精尽 Dubbo 源码分析 —— API 配置相关推荐

  1. dubbo源码分析7 之 服务本地暴露

    在上一篇文章我们分析了一下 dubbo 在服务暴露发生了哪些事,今天我们就来分析一下整个服务暴露中的本地暴露.(PS:其实我感觉本地暴露蛮鸡肋的).本地暴露需要服务提供方与服务消费方在同一个 JVM. ...

  2. Dubbo源码分析:小白入门篇

    关注公众号"java后端技术全栈" 回复"000"获取优质面试资料 大家好,我是老田 答应了小伙伴的Dubbo源码分析系列,今天终于来了,希望不是很晚. 主要也 ...

  3. 志宇-dubbo源码分析

    dubbo源码分析 文档 dubbo加载配置文件 dubboSPI dubbo服务提供 1.校验配置信息 2.创建URL 3.本地注册 4.远程注册 4.1 开启netty服务端 4.2 连接注册中心 ...

  4. 精尽 Redisson 源码分析 —— 限流器 RateLimiter

    1. 概述 限流,无论在系统层面,还是在业务层面,使用都非常广泛.例如说: [业务]为了避免恶意的灌水机或者用户,限制每分钟至允许回复 10 个帖子. [系统]为了避免服务系统被大规模调用,超过极限, ...

  5. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...

  6. Dubbo 源码分析 - 集群容错之 Cluster

    1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...

  7. Dubbo 源码分析 - 集群容错之 Router

    1. 简介 上一篇文章分析了集群容错的第一部分 – 服务目录 Directory.服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由.上一篇文章关于服务路由相关逻辑没有细 ...

  8. Dubbo 源码分析 - 服务导出

    1.服务导出过程 本篇文章,我们来研究一下 Dubbo 导出服务的过程.Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可 ...

  9. Dubbo源码分析:全集整理

    文章目录 一.前言 二.目录 1. 源码篇 2. 衍生篇 一.前言 本文是Dubbo源码分析目录集整理,方便后续查找. 本文持续更新中.文章内容尚在修改中, 受限于个人能力和理解偏差,该系列文章部分内 ...

最新文章

  1. Excel 计算除法并显示为万分之几,如0.15‱
  2. JavaのFile类基础操作之问题
  3. SpringBoot中在普通类里面加载Spring容器中的类
  4. UNITY 打包时提示sdk tools 或 sdk build tools版本低时可以直接点update 按钮进行更新...
  5. python安装与开发环境搭建实验总结_python实验一:python环境配置
  6. Struts2--DomainModel接收参数---使用广泛!!!
  7. 函数指针声明时的形参列表可以没有
  8. hdu 2896 病毒侵袭
  9. 05 切片、迭代、列表生成
  10. redis图形化界面_Redis(六)- Client
  11. Linux 末路,Kubernetes 崛起!
  12. 10.2. Incron - cron-like daemon which handles filesystem events
  13. 牛人开发软件-网站收集
  14. C调用系统命令ping崩溃日志
  15. 微信小程序云数据库增删改查
  16. 企业管理系统各主要模块简介
  17. BZOJ 3503([Cqoi2014]和谐矩阵-gauss消元)
  18. 链表的有序集合(java)
  19. 一个很精致的HelloWorld,你看得懂么?
  20. java poi_Java POI的学习(一)——Word

热门文章

  1. 2020年一级计算机考试试题,2020年2016计算机一级考试考点试题
  2. STM32人脸识别系统设计(程序代码+论文)
  3. 洗礼灵魂,修炼python(51)--爬虫篇—变色龙般的伪装
  4. 齐岳钹形|UFO形|花生形|碗形Janus PS聚合物微球
  5. 获取客户端真实IP方法
  6. 安卓手机远程控制DIY智能家居设备(ESP8266)
  7. Android适配阿拉伯语、波斯语语系
  8. 为matlab GUI添加背景图片
  9. window 10系统修改C盘用户名过程
  10. Qt时间 - QDateTime