IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 浅谈Dubbo服务引入源码(@ReferenceBean依赖注入) -> 正文阅读

[网络协议]浅谈Dubbo服务引入源码(@ReferenceBean依赖注入)


服务引入指的是,我们在使用@Reference获取远程Bean对象的过程。在使用了@Reference注解进行对象的属性填充阶段,Dubbo的属性填充后置处理器ReferenceAnnotationBeanPostProcessor类会调用ReferenceBean的get方法完成属性填充。 我们的故事也就从get方法开始(get方法在ReferenceBean的父类ReferenceConfig类中)

根据方法的层级,整理的方法调用步骤层级.

  • 1、2、3、4在一条调用链上
  • 第5里面会调用第6步
  • 5、7、8在同一个方法的同一级



1、getOrCreateProxy

在通过Spring对含有@Reference注解的属性进行属性填充,会调用到get方法



2、get

get方法位于ReferenceBean的父类ReferenceConfig中。

在该方法中主要进行参数检查,然后掉哦那个init方法

在Dubbo服务导出阶段也含有类似checkAndUpdateSubConfigs这个步骤。调用checkAndUpdateSubConfigs()方法,检查和更新参数,和服务提供者类似,把ReferenceBean里的属性的值更新为优先级最高的参数值



3、init

该方法同样类似Dubbo服务导出阶段逻辑,把消费者所引入服务设置的参数添加到一个map中,等会根据这个map中的参数去从注册中心查找服务,然后对查找到的服务生成一个代理对象,设置到ref参数上。

前面第2步说到的调用get方法,最终返回的也就是这个ref参数所代表的服务代理对象



4、createProxy(核心)

下面提到的5、6、7、8几点,都是在该方法中完成的



5、REF_PROTOCOL.refer

这里主要的逻辑为调用到RegistryProtocol类的refer方法,但是在调到对应的refer方法之前,会先经过相关的包装类ProtocolListenerWrapper和ProtocolFilterWrapper的refer方法。

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {

    // 从registry://的url中获取对应的注册中心,比如zookeeper, 默认为dubbo,dubbo提供了自带的注册中心实现
    // url由 registry:// 改变为---> zookeeper://
    url = URLBuilder.from(url)
            .setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY))
            .removeParameter(REGISTRY_KEY)
            .build();

    // 拿到注册中心实现,ZookeeperRegistry
    Registry registry = registryFactory.getRegistry(url);

    // 下面这个代码,通过过git历史提交记录是用来解决SimpleRegistry不可用的问题
    if (RegistryService.class.equals(type)) {
        return proxyFactory.getInvoker((T) registry, type, url);
    }

    // qs表示 queryString, 表示url中的参数,表示消费者引入服务时所配置的参数
    Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));

    // group="a,b" or group="*"
    // https://dubbo.apache.org/zh/docs/v2.7/user/examples/group-merger/
    String group = qs.get(GROUP_KEY);
    if (group != null && group.length() > 0) {
        if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
            // group有多个值,这里的cluster为MergeableCluster
            return doRefer(getMergeableCluster(), registry, type, url);
        }
    }

    // 这里的cluster是cluster的Adaptive对象,扩展点
    return doRefer(cluster, registry, type, url);
}



6、doRefer(重点)

在该方法中会有一个服务目录的概念,即RegistryDirectory类。

该方法的主题逻辑为:

  1. 根据传入的消费者类型和注册中心url,初始化一个服务目录RegistryDirectory对象
  2. 构建对应的路由器链(可在引入服务时按路由条件进行过滤),并添加到RegistryDirectory中去
  3. 监听Dubobo-admin客户端相关的目录,可用来动态修改服务目录对象的值
  4. 初始化相关的ClusterInvoker对象
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
    // RegistryDirectory表示动态服务目录,会和注册中心的数据保持同步
    // type表示一个服务对应一个RegistryDirectory,url表示注册中心地址
    // 在消费端,最核心的就是RegistryDirectory
    RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
    directory.setRegistry(registry);
    directory.setProtocol(protocol);


    // all attributes of REFER_KEY
    // 引入服务所配置的参数
    Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());

    // 消费者url
    URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
    if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {
        directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url));

        // 注册简化后的消费url
        registry.register(directory.getRegisteredConsumerUrl());
    }

    // 构造路由链,路由链会在引入服务时按路由条件进行过滤
    // 路由链是动态服务目录中的一个属性,通过路由链可以过滤某些服务提供者
    directory.buildRouterChain(subscribeUrl);

    // 服务目录需要订阅的几个路径
    // 当前应用所对应的动态配置目录:/dubbo/config/dubbo/dubbo-demo-consumer-application.configurators
    // 当前所引入的服务的动态配置目录:/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService:1.1.1:g1.configurators
    // 当前所引入的服务的提供者目录:/dubbo/org.apache.dubbo.demo.DemoService/providers
    // 当前所引入的服务的老版本动态配置目录:/dubbo/org.apache.dubbo.demo.DemoService/configurators
    // 当前所引入的服务的老版本路由器目录:/dubbo/org.apache.dubbo.demo.DemoService/routers
    directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
            PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));

    // 利用传进来的cluster,join得到invoker, MockClusterWrapper
    Invoker invoker = cluster.join(directory);
    ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
    return invoker;
}

1)构建路由链

2)监听对应目录

RegistryDirectory.subscribe --> FailbackRegistry.subscribe --> FailbackRegistry.subscribe --> ZookeeperRegistry.doSubscribe

在该方法中,会创建对应的注册中心连接,然后绑定对应的需要监听的路径path。这个path对应的路径就是第一步传进来的url,即包含目录为:

subscribeUrl.addParameter(CATEGORY_KEY,
        PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY)
  • CATEGORY_KEY:服务基础路径/category(老版本目录)
  • PROVIDERS_CATEGORY:服务基础路径/providers(老版本目录)
  • CONFIGURATORS_CATEGORY:服务基础路径/configurators(新版本目录)
  • ROUTERS_CATEGORY:服务基础路径/routers(老版本目录)

3)调用join方法完成对象初始化

添加相关Invoker方法作用:

  • MockClusterInvoker: 完成Mock功能,由MockClusterWrapper生成,MockClusterWrapper是Cluster接口的包装类,通过Cluster.join()方法得到MockClusterInvoker
  • FailoverClusterInvoker:完成集群容错功能,是MockClusterInvoker的下级
  • RegistryAwareClusterInvoker:如果指定了多个注册中心,那么RegistryAwareClusterInvoker完成选择默认的注册中心的进行调用,如果没有指定默认的,则会遍历注册中心进行调用,如果该注册中心没有对应的服务则跳过。
  • DubboInvoker:完成Dubbo协议底层发送数据
  • ProtocolFilterWrapper$CallbackRegistrationInvoker:完成对filter的调用,ProtocolFilterWrapper是Protocol接口的包装类,通过Protocol.refer()方法得到CallbackRegistrationInvoke。



7、CLUSTER.join

将多个或一个invokers根据相关的规则处理得到唯一的一个invoker对象,用于下一步生成对应的代理对象。

这里分为两种情况:

  • 如果这多个urls中存在注册中心url,会调用到RegistryAwareCluster对象,这里含有Cluster的嵌套,会先调用外层Wrapper包装类MockClusterWrapper的join方法,然后在调用wrapper包装类的join方法时,会再调用RegistryAwareCluster的join方法,继而达到嵌套调用的效果。在未来进行服务获取的时候,就会先去执行初始化好的Cluster对象内部的Invoker对象的Invoke方法,就自然而然的含有了Invoker嵌套,会先调用MockClusterInvoker的invoke方法,再调用RegistryAwareClusterInvoker的invoke方法
  • 如果这多个urls中不存在注册中心url,会生成一个FailoverClusterInvoker对象

1、这里只对第一种情况进行说明第一种情况

这里调用的是RegistryAwareCluster类的join方法,join方法会实例化出一个Invoker,最终会调用到每个Invoker的invoke方法。

在wrapper包装Invoker类中,会先进行mock判断,是否需要进行mock处理

这里使用了模板方法模式,在调用类的invoke方法时,会直接调用到其父类AbstractClusterInvoker的invoke方法,然后再执行具体子类的doInvoke方法

在父类就能够完成多个invoker的负载均衡处理



8、getProxy

这里默认使用Javassist代理方式

传入前面过滤后剩下的一个Invoke,为其生成一个代理对象,返回给调用处

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 18:20:11  更:2022-04-18 18:21:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:46:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码