热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Dubbo——路由的实现

路由的实现路由接口会根据用户配置的不同路由策略对Invoker列表进行过滤,只返回符合规则的Invoekr。例如:如果用户配置了接口A的所有调用&#x

路由的实现

路由接口会根据用户配置的不同路由策略对Invoker列表进行过滤,只返回符合规则的Invoekr。例如:如果用户配置了接口A的所有调用,都是用IP为192.168.1.22的节点,则路由会过滤其他的Invoekr,只返回IP为192.168.1.22的Invoker。

路由的总体结构

路由分为条件路由、文件路由、脚本路由,对应dubbo-admin中三种不同的规则匹配方法。

  • 条件路由是用户使用Dubbo定义的语法规则去写路由规则;
  • 文件路由则需要用户提交一个文件,里面写着对应的路由规则,框架基于文件读取对应的规则;
  • 脚本路由则是使用JDK自身的脚本引擎解析路由规则脚本,所有JDK脚本引擎支持的脚本都能解析,默认是Javascript。
    在这里插入图片描述
    在这里插入图片描述

RouterFactory是一个SPI接口,没有设置默认值,但由于有@Adaptive("protocol")注解,因此他会根据URL中的protocol参数确定要初始化哪个具体的Router实现。
在这里插入图片描述

在SPI的配置文件中可以看到,URL中的protocol可以设置file、script、condition三种值:
在这里插入图片描述
RouterFactory的实现也非常简单,就是直接"new"一个对应的Router并返回。例如:ConditionRouterFactory直接"new"并返回一个ConditionRouter。当然,FileRouterFctory除外,直接在工厂类中实现了所有逻辑。

条件路由的参数规则

条件路由使用的是condition://协议,URL形式是:

condition://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=URL.encode("host=10.20.153.0=>host=10.20.153.11")//最后的路由规则会使用URL.encode畸形编码

路由规则:

参数名称含义
condition://表示路由规则的类型,自持条件路由、脚本路由,可扩展,必填
0.0.0.0表示对所有IP地址生效,如果想对某个IP生效,则填入具体IP,必填
com.foo.BarService表示只对指定服务生效,必填
category=routers表示该数据为动态配置类型,必填
dynamic=fales表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填
enable=true覆盖规则是否生效,可不填,默认生效
force=false当路由结果为空时,是否强制执行,如果不强制执行,则路由结果为空的路由将自动失效,可不填,默认为false
runtime=false是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,则必须设为true,需要注意设置会影响调用的性能,可不填,默认为false
priority=1路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,默认为0
rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11")表示路由规则的内容,必填

路由规则配置示例:

method = find* => host = 192.168.1.22

  • 这条配置说明所有调用find开头的方法都会被路由到IP为192.168.1.22的服务节点上;
  • =>之前的部分为消费者匹配条件,将所有参数和消费者的URL进行对比,当消费者满足匹配条件时,对该消费者执行后面的过滤规则;
  • =>之后的部分为提供者地址列表的过滤条件,将所有参数和提供者的URL进行对比,消费者最终只获取过滤后的地址列表;
  • 如果匹配条件为空,则表示应用于所有消费方,如=> host != 192.168.1.22;
  • 如果过滤条件为空,则表示禁止访问,如host = 192.168.1.22 ->;

整个规则的表达式支持$protocol等占位符方式,也支持=、!=等条件。值可以支持多个,有那个逗号分隔,如host = 192.168.1.22,192.168.1.23;如果以"*"号结尾,则说明是通配符,如host = 192.168.1.*表示撇皮192.168.1.网段下所有IP

条件路由的实现

条件路由的具体实现类是ComditionRouter,Dubbo会根据自定义的规则语法来实现路由规则。我们主要需要关注其构造方法和实现父类接口的route方法。

1. ConditionRouter构造方法的逻辑:

ConditionRouterFactory在初始化ConditionRouter的时候,其构造方法汇总含有规则解析的逻辑。步骤如下:

  1. 粮据URL的健rule获取对应的规则字符串,以=>为界,把规则分成两段,前面部分为whenRule,即消费者匹配条件:后面部分为thenRule, 即提供者地址列表的过滤条件。我们以上面的示例规则为例,其会被解析为whenRule method = find*thenRule host = 192.168.1.22

  2. 分别解析两个路由规则。调用parseRule 方法,通过正则表达式不断循环匹配whenRule和thenRule字符串。解析的时候,会根据key-vaue之间的分隔符对key-value做分类(如果A=B,则分隔符为=),支持的分隔符形式有:A=B、 A&B、A!=B、A,B这4种形式。最终参数都会被封装成一个个MatchPair对象,放入Map中保存。Map的key是参数值,value 是MatchPair对象。若以上面的示例规则为例,则会生成以method为key的whenMap,以host为key的then Map。value 则分别是包装了find*和192. 168.1.22的MatchPair对象。

    MatchPair对象是用来做什么的呢?这个对象一共有两个作用。

    • 第一个作用是通配符的匹配和占位符的赋值。MatchPair对象是内部类,里面只有一个isMatch方法,用于判断值是否能匹配得上规则。规则里的$、*等通配符都会在MatchPair对象中进行匹配。其中$支持protocol、username、password、 host、 port、 path 这几个动态参数的占位符。例如:规则中写了S$protocol,则会自动从URL中获取protocol的值,并赋值进去。
    • 第二个作用是缓存规则。MatchPair 对象中有两个Set 集合,一个用于保存匹配的规则,如=find*; 另一个则用于保存不匹配的规则,如!=find*。这两个集合在后续路由规则匹配的时候会使用到。

2. route方法的实现原理:

ConditionRouter继承了Router 接口,需要实现接口的route方法。该方法的主要功能是过滤出符合路由规则的Invoker列表,即做具体的条件匹配判断,其步骤如下:

  1. 校验。如果规则没有启用,则直接返回;如果传入的Invoker列表为空,则直接返回空:如果没有任何的whenRule匹配,即没有规则匹配,则直接返回传入的Invoker列表:如果whenRule有匹配的,但是thenRule 为空,即没有匹配上规则的Invoke,则返回空。

  2. 遍历Invoker列表,通过heRule找出所有符合规则的Invoker加入集合。例如:匹配规则中的method名称和当前URL中的method是不是相等。

  3. 返回结果。如果结果集不为空,则直接返回:如果结果集为空,但是规则配置了frcerue即强制过滤,那么就会返回空结果集:非强制则不过滤,即返回所有lnoer列表。具体的逻辑还,是比较简单的,但代码中的if判断会比较多。


文件路由的实现

文件路由是把规则写在文件中,文件中写的是自定义的脚本规则,可以是Javascript、Groovy等,URL中对应的key值填写的是文件的路径。文件路由主要做的就是把文件中的路由脚本读出来,然后调用路由的工厂去匹配对应的脚本路由做解析。

在这里插入图片描述

脚本路由的实现

脚本路由使用JDK自带的脚本解析器解析脚本并运行,默认使用Javascript解析器,其逻辑分为构造方法和route方法两大部分。构造方法主要负责一些初始化的工作,route方法则是具体的过滤逻辑执行的地方。

脚本示例:

function route(invokers) {//创建一个Listvar result &#61; new java.util.ArrayList(invokers.size());//遍历传入的所有Invoker&#xff0c;过滤所有IP不死10.20.153.10的Invokerfor(i &#61; 0; i < invokers.size(); i&#43;&#43;) {if("10.20.153.10".equals(invokers.get(i).getUrl().getHost())){result.add(invokers.get(i));}}return result;
}(invokers);//表示立即执行方法

在写Javascript脚本的时候需要注意&#xff0c;一个服务只能有一条规则&#xff0c;如果有多条规则&#xff0c;并且规则之间没有交集&#xff0c;则会把所有的Invoker都过滤。另外&#xff0c;脚本路由中也没看到沙箱约束&#xff0c;因此会有注入的风险。

脚本路由的构造方法逻辑&#xff1a;

  1. 初始化参数。获取规则的脚本类型、路由优先级。如果没有设置脚本类型&#xff0c;则默认设置为Javascript类型&#xff0c;如果没有解析到任何规则&#xff0c;则抛出异常。
  2. 初始化脚本执行引擎。根据脚本的类型&#xff0c;通过Java的ScriptEngineManager创建不同的脚本执行器&#xff0c;并缓存起来。

route方法的核心逻辑就是调用脚本引擎&#xff0c;获取执行结果并返回。主要是JDK脚本引擎的调用&#xff0c;不会涉及具体的过滤逻辑。

在这里插入图片描述
在这里插入图片描述


推荐阅读
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
author-avatar
手机用户2502863963
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有