1:写在前面

在这篇文章 中我们分析了服务提供者配置的相关源码,本文一起来看下服务消费者配置相关的源码,还是看一个通过API 方式配置服务消费者的实例代码:

public class ConsumerWithApiConfigMain {public static void main(String[] args) {// 当前应用配置ApplicationConfig application = new ApplicationConfig();application.setName("dongshidaddy-consumer");application.setOwner("dongshidaddy");// 连接注册中心配置RegistryConfig registry = new RegistryConfig();registry.setAddress("zookeeper://192.168.10.119:2181");// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接// 引用远程服务ReferenceConfig<ProviderService> reference = new ReferenceConfig<ProviderService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏reference.setApplication(application);reference.setRegistry(registry); // 多个注册中心可以用setRegistries()reference.setInterface(ProviderService.class);// 和本地bean一样使用xxxServiceProviderService providerService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用String s = providerService.SayHello("hello dubbo! I am dongshidadddy!");System.out.println(s);}
}

下面我们来一起看下其中使用到的配置类。

2:ConsumerConfig

类全限定名是com.alibaba.dubbo.config.ConsumerConfig,主要源码如下:

public class ConsumerConfig extends AbstractReferenceConfig {private static final long serialVersionUID = 2827274711143680600L;private Boolean isDefault;// 客户端的类型,netty,mina等private String client;// 消费者线程池类型,如cached,fixed,limit,eager等private String threadpool;// 消费者核心线程池大小private Integer corethreads;// 消费者线程池大小private Integer threads;// 消费者任务队列大小private Integer queues;
}

对应的标签是dubbo:consumer ,可能的配置如<dubbo:consumer client="netty" corethreads="20">

3:ReferenceConfig

类全限定名是com.alibaba.dubbo.config.ReferenceConfig,源码如下:

public class ReferenceConfig<T> extends AbstractReferenceConfig {private static final long serialVersionUID = -5864351140409987595L;private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();private final List<URL> urls = new ArrayList<URL>();// 服务接口名称private String interfaceName;private Class<?> interfaceClass;// 客户端类型private String client;// url for peer-to-peer invocationprivate String url;// method configsprivate List<MethodConfig> methods;// <dubbo:consumer>private ConsumerConfig consumer;private String protocol;// interface proxy referenceprivate transient volatile T ref;private transient volatile Invoker<?> invoker;private transient volatile boolean initialized;private transient volatile boolean destroyed;
}

通过开始的实例代码可以看到最终获取服务提供者的服务类是通过方法ReferenceConfig#get,主要做了以下几件事:

1:进一步初始化和校验ReferenceConfig。
2:使用ReferenceConfig,生成DUBBO URL数组。
3:使用DUBBO URL应用服务。

get方法源码如下:

// com.alibaba.dubbo.config.ReferenceConfig.get
class FakeCls {public synchronized T get() {// 是否已经销毁,如果是已经销毁的话,抛出java.lang.IllegalStateExceptionif (destroyed) {throw new IllegalStateException("Already destroyed!");}// private transient volatile T ref; 还没有初始化才进行初始化if (ref == null) {// 2021-12-02 10:31:11init();}return ref;}
}

2021-12-02 10:31:11处是进行服务代理类的初始化,详细参考3.1:init

3.1:init

源码如下:

// com.alibaba.dubbo.config.ReferenceConfig.init
class FakeCs {private void init() {// 已经初始化if (initialized) {return;}// 将初始化的标记设置为true,防止重复初始化initialized = true;// 没有设置服务接口,即<dubbo:reference interface="">的情况,抛出java.lang.IllegalStateExceptionif (interfaceName == null || interfaceName.length() == 0) {throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");}// 添加环境变量配置的外部属性到ConsumerConfig中,即<dubbo:consumer>checkDefault();// 添加环境变量配置的外部属性到PreferenceConfig,即<dubbo:reference>appendProperties(this);// 泛化接口,如是是在<dubbo:reference>中没有配置,且配置了<dubbo:consumer>则从<dubbo:consumer>中获取// 默认为false,即不是泛化接口if (getGeneric() == null && getConsumer() != null) {setGeneric(getConsumer().getGeneric());}// 如果是泛化接口,则设置接口类型为GenericService.class,判断如下:/*public static boolean isGeneric(String generic) {return generic != null&& !"".equals(generic)&& (Constants.GENERIC_SERIALIZATION_DEFAULT.equalsIgnoreCase(generic) // public static final String GENERIC_SERIALIZATION_DEFAULT = "true";|| Constants.GENERIC_SERIALIZATION_NATIVE_JAVA.equalsIgnoreCase(generic) // public static final String GENERIC_SERIALIZATION_NATIVE_JAVA = "nativejava";|| Constants.GENERIC_SERIALIZATION_BEAN.equalsIgnoreCase(generic)); // public static final String GENERIC_SERIALIZATION_BEAN = "bean";}*/if (ProtocolUtils.isGeneric(getGeneric())) {interfaceClass = GenericService.class;} else {// 普通服务接口,根据接口名称获取class对象try {interfaceClass = Class.forName(interfaceName, true, Thread.currentThread().getContextClassLoader());} catch (ClassNotFoundException e) {throw new IllegalStateException(e.getMessage(), e);}// 检测<dubbo:reference>中配置的<dubbo:method>是否在接口中真的存在checkInterfaceAndMethods(interfaceClass, methods);}// ***直连提供者逻辑开始*** //// 这种是配置 java -D com.jh.xxx.XxxService=dubbo://192.168.10.119:20880 xxx.jarString resolve = System.getProperty(interfaceName);String resolveFile = null;// 没有配置java -D com.jh.xxx.XxxService=dubbo://192.168.10.119:20880 xxx.jarif (resolve == null || resolve.length() == 0) {// 获取配置文件,如System.setProperty("dubbo.resolve.file", "/etc/app/dubbop2p.properties"):/*/etc/app/dubbop2p.properties示例内容:com.jh.xxx.XxxService=dubbo://192.168.10.119:20880com.jh.xxx.YyyService=dubbo://192.168.10.119:20880*/resolveFile = System.getProperty("dubbo.resolve.file");// 如果是没有设置System.setProperty("dubbo.resolve.file", "/etc/app/dubbop2p.properties");if (resolveFile == null || resolveFile.length() == 0) {// 获取user.home环境变量下的dubbo-resolve.properties文件,如C:\Users\Administrator\dubbo-resolve.propertiesFile userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");if (userResolveFile.exists()) {resolveFile = userResolveFile.getAbsolutePath();}}// 在System.getProperty("user.home")下有dubbo-resolve.propertiesif (resolveFile != null && resolveFile.length() > 0) {// 将System.getProperty("user.home")/dubbo-resolve.properties文件内容加载到java.util.Properties中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);}}// 获取配置的dubbo urlresolve = properties.getProperty(interfaceName);}}// 主要是给出警告日志,和警告提示if (resolve != null && resolve.length() > 0) {url = resolve;if (logger.isWarnEnabled()) {// resolveFile != null说明是通过System.getProperty("user.home")/dubbo-resolve.properties文件获取的dubbo url,给出相应的日志提示// 否则是通过java -Dcom.jh.xxx.XxxService=dubbo://192.168.10.119:20880 xxx.jar 获取的dubbo url,给出相应的日志提示// 因为到底dubbo url是如何获取的直接影响了整个消费者的调用,所以使用了warn级别的日志来进行打印if (resolveFile != null) {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.");}}}// ***直连提供者逻辑结束*** //// ***获取各种config开始*** //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();}}if (module != null) {if (registries == null) {registries = module.getRegistries();}if (monitor == null) {monitor = module.getMonitor();}}if (application != null) {if (registries == null) {registries = application.getRegistries();}if (monitor == null) {monitor = application.getMonitor();}}// ***获取各种config结束*** //// 追加系统属性到application配置中checkApplication();// 检查stubcheckStub(interfaceClass);// 检查mockcheckMock(interfaceClass);// 生成consumer:// url的参数的字典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.getProtocolVersion());map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));// 设置jvm进程号if (ConfigUtils.getPid() > 0) {map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));}// 不是泛化接口,则需要设置方法信息if (!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);// 追加application配置信息到参数字典中appendParameters(map, application);// 追加module配置信息到参数字典中appendParameters(map, module);// 追加consumer配置信息到参数字典中appendParameters(map, consumer, Constants.DEFAULT_KEY);// 追加自己,即reference配置到参数字典中appendParameters(map, this);String prefix = StringUtils.getServiceKey(map);// 处理<dubbo:method>的配置信息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");}}// 将配置了@Parameter(attribute=true)的参数添加到attributes中appendAttributes(attributes, method, prefix + "." + method.getName());// 2021-12-03 13:47:05checkAndConvertImplicitConfig(method, map, attributes);}}// 使用DUBBO_IP_TO_REGISTRY作为注册到注册中心的地址String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY);// 没有配置,则获取本机网卡IP地址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);//attributes are stored by system context.StaticContext.getSystemContext().putAll(attributes);// 应用服务,暂时忽略// ...}
}

2021-12-03 13:47:05处是检查事件通知 配置是否正确,源码如下:

// checkAndConvertImplicitConfig
class FakeCls {private static void checkAndConvertImplicitConfig(MethodConfig method, Map<String, String> map, Map<Object, Object> attributes) {// 是否设置了<dubbo:method return="false" async="true">即不需要返回值,因为这种情况直接异步返回null,而不管后续执行情况,所以如果配置了onreutn,onthrow等和执行结果有关系的内容则异常// 详细参考:https://dubbo.apache.org/zh/docs/references/xml/dubbo-method/ 搜索”<methodName>.return“if (Boolean.FALSE.equals(method.isReturn()) && (method.getOnreturn() != null || method.getOnthrow() != null)) {throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been setted.");}// 转换onreturn为对应的java.lang.reflect.MethodString onReturnMethodKey = StaticContext.getKey(map, method.getName(), Constants.ON_RETURN_METHOD_KEY);Object onReturnMethod = attributes.get(onReturnMethodKey);if (onReturnMethod instanceof String) {attributes.put(onReturnMethodKey, getMethodByName(method.getOnreturn().getClass(), onReturnMethod.toString()));}// 转换onthrow为对应的java.lang.reflect.MethodString onThrowMethodKey = StaticContext.getKey(map, method.getName(), Constants.ON_THROW_METHOD_KEY);Object onThrowMethod = attributes.get(onThrowMethodKey);if (onThrowMethod instanceof String) {attributes.put(onThrowMethodKey, getMethodByName(method.getOnthrow().getClass(), onThrowMethod.toString()));}// 转换onInvoke为对应的java.lang.reflect.MethodString onInvokeMethodKey = StaticContext.getKey(map, method.getName(), Constants.ON_INVOKE_METHOD_KEY);Object onInvokeMethod = attributes.get(onInvokeMethodKey);if (onInvokeMethod instanceof String) {attributes.put(onInvokeMethodKey, getMethodByName(method.getOninvoke().getClass(), onInvokeMethod.toString()));}}
}

dubbo之服务消费者配置相关推荐

  1. springboot dubbo 多模块项目dubbo提供者和消费者配置及代码

    注:本文只是介绍我成功使用springboot dubbo 多模块项目的配置及核心代码,若问题没得到解决或需要可运行的源码,文章末尾有说明. springboot集成dubbo过程坑太多,dubbo提 ...

  2. Dubbo(十二)dubbo的服务版本配置以及本地存根使用介绍

    一.接口服务多版本管理 在实际项目场景中在发布生产之前会存在一个过渡的灰度版本环境,dubbo也一样在接口服务升级时,可以实现两个版本的服务接口,指定不同的版本号.当少量的消费端调用引用高版本后使用无 ...

  3. dubbo k8s 服务发现_工商银行基于 Dubbo 构建金融微服务架构的实践-服务发现篇

    作者 | 张远征来源|阿里巴巴云原生公众号 导读:Dubbo 作为分布式微服务框架,众多公司在实践中基于 Dubbo 进行分布式系统架构.重启开源后,我们不仅看到 Dubbo 3.0 最新的 Road ...

  4. 记录一下曾经写过的P2P金融项目-理财端(PC端)纯代码(续-服务消费者工程)

    pom文件: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3 ...

  5. SpringCloud-创建服务消费者-Ribbon方式(附代码下载)

    场景 SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  6. Dubbo搭建HelloWorld-搭建服务提供者与服务消费者并完成远程调用(附代码下载)

    场景 Dubbo简介与基本概念: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555224 Dubbo环境搭建-ZooKe ...

  7. 源码分析Dubbo前置篇-寻找注册中心、服务提供者、服务消费者功能入口

    本节主要阐述如下两个问题:  1.Dubbo自定义标签实现.  2.dubbo通过Spring加载配置文件后,是如何触发注册中心.服务提供者.服务消费者按照Dubbo的设计执行相关的功能.  所谓的执 ...

  8. Spring Cloud Alibaba配置实例nacos+sentinel+dubbo实行服务注册、配置中心、熔断限流

    通过Spring Cloud Alibaba相关组件nacos+sentinel+dubbo实行服务注册.配置中心.熔断限流等功能 1.本机安装nacos和sentinel-dashboard服务端 ...

  9. Dubbo源码解析-Dubbo服务消费者_Dubbo协议(一)

    前言: 在介绍完Dubbo 本地模式(Injvm协议)下的服务提供与消费后,上文我们又介绍了Dubbo远程模式(dubbo协议)下的服务暴露过程,本质上就是通过Netty将dubbo协议端口暴露出去, ...

最新文章

  1. LeetCode:Remove Nth Node From End of List
  2. jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .
  3. idea学生认证用了一年后过期了怎么办?
  4. LightOJ 1259 Goldbach`s Conjecture 素数打表
  5. 天猫双11倒计时:80000瓶1499元53度飞天茅台将开放限量抢购
  6. Lotus Notes 中导航的键盘快捷方式
  7. Sql分页存储过程(支持多表分页存储)
  8. 网页设计中常用的Web安全字体
  9. 基于模糊PID控制的光伏系统最大功率点跟踪的研究
  10. VMP3.6的反调试和反虚拟机
  11. jracdrive变频器说明书580_ABB变频器ACS580说明书.pdf
  12. 韩语在线翻译图片识别_最强文字识别APP
  13. Linux嵌入式和单片机嵌入式到底什么区别?
  14. 算法学习 | 期望dp+概率dp
  15. IT 必备电脑快捷键
  16. openerp换mysql_OpenERP 源码变更后数据库升级
  17. Nginx同一个域名下代理后端项目跟多个vue项目
  18. d2l.Vocab(sentences, min_freq=5, reserved_tokens=[‘<pad>‘, ‘<mask>‘, ‘<cls>‘, ‘<sep>‘]) 参数讲解
  19. 线性代数-思维导图(5)
  20. java中bean的作用域有哪些_Spring中Bean的5种作用域scope详解

热门文章

  1. 总结:Java探针技术
  2. AXI4设计重点002_易出错的地址非对齐读操作
  3. (附源码)ssm高校学生宿舍管理系统 毕业设计051443
  4. 【C++】C++基础 —— 变量和基本类型
  5. cgb二三阶面试题集(mysql mybatis MVC... MVVM)
  6. IDEA小技巧——Shelve
  7. 物流管理和计算机那个专业好,我是学计算机的女生,想跨专业考物流管理专业的研究生,好不好?...
  8. 这6种开源协议(GPL,LGPL,BSD,MIT,Apache)
  9. Vuetify下载图片的问题探究
  10. Python 小技之繁花曲线