soul 源码分析 —— 插件解析之选择器

soul网关-7-waf插件 之前的一篇学习Divide插件的笔记里面分析过插件链,waf插件是插件链上排在sign插件后面的第二个插件。 WafPlugin也继承自AbstractSoulPlugin,但在AbstractSoulPlugin的execute方法里面对waf插件与其他插件如divide插件稍有不同。 divide插件在AbstractSoulPlugin的execute方法里面的处理过程是: 判断内存缓存中是否有插件数据,没有则执行下一个插件 判断插件数据中是否启用的标志位是否为true,否则执行下一个插件 插件数据 阅读详情

选择器定义

选择器是什么?

soul选择器就是网关的过滤器,所有的网关请求都会经过选择器功能进行路由断言,所有选择器匹配规则都通过后,才能进行下一步的请求。

soul网关还有一个规则的概念,规则也是实施网关请求的过滤。规则与选择器的条件设置基本一样。

那选择器和规则有什么不同?

选择器可以看成是粗粒度的路由断言,比如:/http/**

规则可以看成是进一步的路由断言,比如:/http/order/findById

可以理解为:选择器相当于是对流量的第一次筛选,规则就是最终的筛选。

选择器和规则都必须满足,网关请求才能进一步往下走。

选择器详解

在这里插入图片描述

选择器详解:

  • 名称:为你的选择器起一个容易分辨的名字
  • 类型:custom flow 是自定义流量。full flow 是全流量。自定义流量就是请求会走你下面的匹配方式与条件。全流量则不走。
  • 匹配方式:and 或者or 是指下面多个条件是按照and 还是or的方式来组合。
  • 条件:
    • uri:是指你根据uri的方式来筛选流量,match的方式支持模糊匹配(/**)
    • header:是指根据请求头里面的字段来筛选流量。
    • query:是指根据uri的查询条件来进行筛选流量。
    • ip:是指根据你请求的真实ip,来筛选流量。
    • host:是指根据你请求的真实host,来筛选流量。
    • post:建议不要使用。
    • 条件匹配:
      • match:模糊匹配,建议和uri条件搭配,支持 restful风格的匹配。(/test/**)
      • =:前后值相等,才能匹配。
      • regEx:正则匹配,表示前面一个值去匹配后面的正则表达式。
      • like:字符串模糊匹配。
  • 是否开启:打开才会生效
  • 打印日志:打开的时候,当匹配上的时候,会打印匹配日志。
  • 执行顺序:当多个选择器的时候,执行顺序小的优先执行。

选择器分析

选择器处理逻辑流程图:
在这里插入图片描述

1.选择器匹配开始处理

在AbstractSoulPlugin 类的 matchSelector(exchange, selectors),开始选择器匹配处理:

public abstract class AbstractSoulPlugin implements SoulPlugin {

    protected abstract Mono<Void> doExecute(ServerWebExchange exchange, SoulPluginChain chain, SelectorData selector, RuleData rule);

    @Override
    public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        // 获取当前插件的名称
        String pluginName = named();
        // 根据插件名获取插件数据
        final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
        // 如果插件数据信息不为空 并且 该插件启用
        if (pluginData != null && pluginData.getEnabled()) {
            // 根据插件名获取路由选择器数据
            final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
            // 如果不存在插件对应的选择器,并且插件名称是:divide、dubbo、springCloud;返回:can not match selector data: {插件}
            if (CollectionUtils.isEmpty(selectors)) {
                return handleSelectorIsNull(pluginName, exchange, chain);
            }
            // 匹配路由选择器条件
            final SelectorData selectorData = matchSelector(exchange, selectors);
            // 如果匹配不到对应的选择器,并且插件名称是:divide、dubbo、springCloud;返回:can not match selector data: {插件}
            if (Objects.isNull(selectorData)) {
                return handleSelectorIsNull(pluginName, exchange, chain);
            }
            // 路由对应选择器日志输出:{插件} selector success match , selector name :{选择器}
            selectorLog(selectorData, pluginName);
            // 根据插件id,获取路由选择器对应的规则
            final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
            // 如果获取路由选择器对应的规则为空,返回:can not match rule data: {插件}
            if (CollectionUtils.isEmpty(rules)) {
                return handleRuleIsNull(pluginName, exchange, chain);
            }
            RuleData rule;
            // 如果是全流控,不需要进一步的选择器限制规则
            if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
                //get last
                rule = rules.get(rules.size() - 1);
            } else {
                rule = matchRule(exchange, rules);
            }
            // 如果匹配不到路由规则,返回:can not match rule data: {插件}
            if (Objects.isNull(rule)) {
                return handleRuleIsNull(pluginName, exchange, chain);
            }
            // 输出:{} selector success match , selector name :{}
            ruleLog(rule, pluginName);
            // 执行当前插件的doExecute方法
            return doExecute(exchange, chain, selectorData, rule);
        }
        // 插件不存在或者没有启用,调用下一个插件
        return chain.execute(exchange);
    }
    ...
}

通过方法matchSelector(exchange, selectors);,开始匹配选择器处理。

selectors: 为要过滤的选择器数组

matchSelector的具体代码如下:

private SelectorData matchSelector(final ServerWebExchange exchange, final Collection<SelectorData> selectors) {
        return selectors.stream()
                .filter(selector -> selector.getEnabled() && filterSelector(selector, exchange))
                .findFirst().orElse(null);
    }

    private Boolean filterSelector(final SelectorData selector, final ServerWebExchange exchange) {
        // 如果选择器是自定义流量
        if (selector.getType() == SelectorTypeEnum.CUSTOM_FLOW.getCode()) {
            // 如果不存在选择器条件,返回false
            if (CollectionUtils.isEmpty(selector.getConditionList())) {
                return false;
            }
            return MatchStrategyUtils.match(selector.getMatchMode(), selector.getConditionList(), exchange);
        }
        // 如果选择器是全流量,不做匹配控制,
        return true;
    }

遍历选择器数组,进行如下判断:

FULL_FLOW: 如果是全流量,即不做任何匹配条件限制
CUSTOM_FLOW:自定义流量,根据配置的条件匹配
2.选择器匹配方式选择
    public static boolean match(final Integer strategy, final List<ConditionData> conditionDataList, final ServerWebExchange exchange) {
        // 获取匹配方式:0:and;1:or
        String matchMode = MatchModeEnum.getMatchModeByCode(strategy);
        // 如果匹配方式为and,则加载AndMatchStrategy
        // 如果匹配方式为or,则加载OrMatchStrategy
        MatchStrategy matchStrategy = ExtensionLoader.getExtensionLoader(MatchStrategy.class).getJoin(matchMode);
        // 调用匹配方式的match方法,进行选择器的匹配
        return matchStrategy.match(conditionDataList, exchange);
    }
}

匹配方式,支持两种:

and: 所有的匹配条件都成立,选择器匹配才算成功

or: 只要一个匹配条件成立,选择器匹配就算成功

  • 通过spi的方式,进行匹配方式选择
  • 如果匹配方式为and,则加载AndMatchStrategy
  • 如果匹配方式为or,则加载OrMatchStrategy

3.匹配方式处理

    @Override
    public Boolean match(final List<ConditionData> conditionDataList, final ServerWebExchange exchange) {
        return conditionDataList
                .stream()
                .allMatch(condition -> OperatorJudgeFactory.judge(condition, buildRealData(condition, exchange)));
    }

如果匹配方式为:AndMatchStrategy

需要做两件事:

1)遍历每个匹配条件

2)获取请求的真实匹配条件值,接着进行操作符类的处理

4.获取真实的匹配条件值
String buildRealData(final ConditionData condition, final ServerWebExchange exchange) {
        // 假设当前condition为:ConditionData(paramType=uri, operator=match, paramName=/, paramValue=/test-http/**)
        String realData = "";
        // 获取请求类型
        ParamTypeEnum paramTypeEnum = ParamTypeEnum.getParamTypeEnumByName(condition.getParamType());
        switch (paramTypeEnum) {
            case HEADER:
                final HttpHeaders headers = exchange.getRequest().getHeaders();
                final List<String> list = headers.get(condition.getParamName());
                if (CollectionUtils.isEmpty(list)) {
                    return realData;
                }
                realData =                         Objects.requireNonNull(headers.get(condition.getParamName())).stream().findFirst().orElse("");
                break;
            case URI:
                // 如果请求:http://localhost:9195/http/order/findById?id=9
                // realData:/http/order/findById
                realData = exchange.getRequest().getURI().getPath();
                break;
            case QUERY:
                final MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
                realData = queryParams.getFirst(condition.getParamName());
                break;
            case HOST:
                realData = HostAddressUtils.acquireHost(exchange);
                break;
            case IP:
                realData = HostAddressUtils.acquireIp(exchange);
                break;
            case POST:
                final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
                realData = (String) ReflectUtils.getFieldValue(soulContext, condition.getParamName());
                break;
            default:
                break;
        }
        return realData;
    }

匹配的条件包括:post、uri、query、host、ip、header

所有值的获取都是通过设置的匹配条件的key,去获取真实请求的值。

5.操作符类型的获取
public class OperatorJudgeFactory {

    private static final Map<String, OperatorJudge> OPERATOR_JUDGE_MAP = Maps.newHashMapWithExpectedSize(4);

    // 初始化四种判断规则:"="、"match"、"like"、"regEx"
    static {
        OPERATOR_JUDGE_MAP.put(OperatorEnum.EQ.getAlias(), new EqOperatorJudge());
        OPERATOR_JUDGE_MAP.put(OperatorEnum.MATCH.getAlias(), new MatchOperatorJudge());
        OPERATOR_JUDGE_MAP.put(OperatorEnum.LIKE.getAlias(), new LikeOperatorJudge());
        OPERATOR_JUDGE_MAP.put(OperatorEnum.REGEX.getAlias(), new RegExOperatorJudge());
    }

    /**
     * judge request realData has by pass.
     * @param conditionData condition data
     * @param realData       realData
     * @return is true pass   is false not pass
     */
    public static Boolean judge(final ConditionData conditionData, final String realData) {
        // eg:ConditionData(paramType=uri, operator=match, paramName=/, paramValue=/test-http/**)
        // eg:realData(/http/order/findById)
        if (Objects.isNull(conditionData) || StringUtils.isBlank(realData)) {
            return false;
        }
        // OPERATOR_JUDGE_MAP.get(conditionData.getOperator()): 生成操作符判断类
        // 操作符判断类为:EqOperatorJudge、MatchOperatorJudge、LikeOperatorJudge、RegExOperatorJudge
        return OPERATOR_JUDGE_MAP.get(conditionData.getOperator()).judge(conditionData, realData);
    }
}

通过用户设置的匹配条件操作符,获取对应的操作符类。

操作符支持:"="、“match”、“like”、“regEx”

通过OPERATOR_JUDGE_MAP数组,获取操作符实例

6.操作符类进行判断处理
public class MatchOperatorJudge implements OperatorJudge {

    // eg:ConditionData(paramType=uri, operator=match, paramName=/, paramValue=/test-http/**)
    // eg:realData(/http/order/findById)
    @Override
    public Boolean judge(final ConditionData conditionData, final String realData) {
        // 如果请求过滤类型为:uri,走下面的处理方式
        if (Objects.equals(ParamTypeEnum.URI.getName(), conditionData.getParamType())) {
            return PathMatchUtils.match(conditionData.getParamValue().trim(), realData);
        }
        return realData.contains(conditionData.getParamValue().trim());
    }
}

如果获取的操作符是"match",则进行匹配条件值与真实请求值的比较

  • 如果请求条件是uri,则进行特殊处理

    public static boolean match(final String matchUrls, final String path) {
        return Splitter.on(",").omitEmptyStrings().trimResults().splitToList(matchUrls).stream().anyMatch(url -> reg(url, path));
    }
    

    ​matchUrls:用户在后台配置的uri条件:比如:/test-http/**
    uri可以是多个,以逗号隔开,只要其中一个匹配上,即返回true

  • 如果是其它请求条件,即:post、query、host、ip、header,则进行contains方法处理即可

操作符处理完之后,匹配条件的结果也就完成了。

如果匹配方式是and:需要多个匹配的结果成立,才能返回匹配条件;

如果匹配方式是or:只需要一个匹配的结果成立,就能返回匹配条件;

至此,选择器匹配就完成了。

Soul网关源码分析-0期(预热) 启动 soul-admin成功后, 启动soul-bootstrap soul-admin下打印几行信息 2021-01-13 23:00:42.047 INFO 16544 --- [0.0-9095-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-01-13 23:00:42.047 INFO 16544 --- [0.0 阅读详情

相关推荐

soul源码阅读(八)插件流程梳理

目录 背景介绍 网关启动插件的工作流程 客户端请求网关后各插件的处理流程 总结 背景介绍 前面三篇文章 soul源码阅读(五)Spring Cloud应用示例运行 soul源码阅读(六)Spring Cloud应用示例运行续 soul源码阅读(七)Spring Cloud应用示例运行续2 我们通过以下两个问题: 一:{"code":-107,"message":"Can not find selector, please check your configuration!","data

he_cha_bu的博客 1826

【Soul源码阅读】16.启动多台admin,多个网关,形成一个集群

目录 1.启动多台 soul-admin 2.启动多台 soul-bootstrap 3.启动多台业务系统 4.验证同步 4.1 负载均衡 4.2 数据同步 1.启动多台 soul-admin 修改配置文件,把可以开启允许并行执行的复选框。 application.yml server: port: 9095 server: port: 9096 启动后状态: 2.启动多台 soul-bootstrap 跟上面的一样,修改配置文件,打开并行执行的开关。.

hellboy0621的博客 583

Soul源码分析–soul-admin源码分析

Soul源码分析–soul-admin源码分析前言源码分析总结 前言 在上一篇文章中,介绍了 soul-admin 怎么管理和配置网关的请求,其核心原理是基于各种插件来实现对应的功能。现在我们来看看后台是怎么来管理和实现动态配置。 源码分析 在分析源码之前,先看下图,页面显示加载的插件列表会对应后端的请求,根据后端请求,找到对应的controller类 然后找到对应的方法,在上图可以看到这里是访问 plugin 中默认为空的 mapping,传入到分页相关的参数,然后去查询数据库中对应的插件记录 数据库

yutanbo123的博客 513

Soul网关源码分析-3期(吐血分析)

分析选择器 - 一个让人感动的算法 首先分别启动 soul-admin 、soul-bootstrap , 再启动两个相同的test服务组建集群 soul-test-http. 转到后台管理页的 Divide 插件页, 已经注册了的选择器 http 中, 可以看到两个服务路径的配置: 前置工作准备就绪, 在 DividePlugin 插件这打个断点, 看看 selector 的此时内容: SelectorData(id=1349650852775989248, pluginId=5, pluginNam

zm469568595的博客 1688

Soul源码分析–soul-admin入门

Soul源码分析–soul-admin运行使用原理介绍 运行 上一篇介绍过 soul-admin 启动有两种数据库选择,一种是MySQL, 一种是内存H2数据库。如果本地有MySQL,建议还是使用MySQL数据库,毕竟等下我们还是需要看看 soul-admin 启动时创建的表结构。 启动后我们选择"插件列表"->“divide”,如果没有启动别的服务,这个菜单里面应该是空的。 这里我们还要启动 Soul 网关主要的服务 soul-bootstrap,如果不想自己写业务服务来测试,需要把 soul-e

yutanbo123的博客 752

Soul源码分析 —— 调试环境搭建

Soul源码分析 —— 调试环境搭建依赖工具源码拉取本地部署数据初始化登陆admin界面模块依赖和代码 依赖工具 Maven Git JDK IntelliJ IDEA 源码拉取 git clone git@github.com:dromara/soul.git 使用Intellij打开项目,等待maven自动拉下依赖之后执行 mvn install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Drat.skip=true -Dcheckstyle.s

allen1128的博客 651

soul网关源码分析之-限流插件

目标 集成限流(rate_limiter)插件 压测接口触发限流 soul网关限流插件源码分析 总结 简介Soul网关限流插件 ​ soul网关的限流插件是对流量管控的核心,soul网关的限流粒度可以是接口或者参数级别,soul网关的限流插件是基于redis实现的令牌桶算法,所以在集成soul网关之前要搭建一个redis。 网关集成限流插件 pom <dependency> <groupId>org.dromara</groupId>

qq_31279701的博客 1121

Soul网关源码分析-4期(周总结)

文章目录插件链总结AbstractSoulPluginSoulPluginChain插件项目结构DividePlugin负载均衡HashRandomLoadBalanceRoundRobinLoadBalanceWebClientPluginWebClientResponseClient 插件链总结 从一个类关系图说起: #mermaid-svg-rfFm5KqOF5xWodc6 .label{font-family:'trebuchet ms', verdana, arial;font-family:

zm469568595的博客 851

soul 源码分析 —— 插件解析之GlobalPlugin插件

GlobalPlugin插件 GlobalPlugin插件是soul所有插件执行前,最先执行的一个插件。 作用是构建一个soul的上下文环境。 SoulContext soul的上下文环境,由GlobalPlugin插件来构建 public class SoulContext implements Serializable { /** * is module data. */ private String module; /** * is metho

cj271230的博客 817

Soul源码分析--一次请求的旅行之路

Soul源码分析--一次请求的旅行之路divide 插件原理 我们知道soul是一个异步的、高性能的、跨语言的、响应式的API网关,既然做为一个网关,当然是需要对外暴露,接收外部请求,然后转发到后端真实的机器,这一篇就来分析一下,一个请求经过网关会经历什么,最后安全到达目的地。 divide 插件原理 这里先来看看 divide 插件的原理,这里的启动 admin、bootstrap、excample-http 项目的骚操作就不说了。 首先配置好选择器的规则,这里选择默认的随机访问负载策略,然后访问 h

yutanbo123的博客 304

Allegro中调整差分对等长的步骤介绍

【代码】Allegro中调整差分对等长的步骤介绍。

qq_30882617的博客 3832

Soul 网关源码分析(二)divide, rewrite 插件

在上一节里我们编译好了 Soul 网关的源码,今天我们从rewrite插件开始学习如何对服务进行代理并重写路径。 首先我们用Python写一个简单的Flask应用: from flask import Flask app = Flask(__name__) @app.route('/foo/bar/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() 启动服务后,我们可以看

头脑快乐 978

一文讲清CAN和CANFD的区别

本文将从技术原理、协议特性到应用场景,深度解析两者的核心差异。

文章主要涉及嵌入式软件开发、测试、项目管理等,欢迎交流,共同进步。 3204

soul网关源码分析之soul-gateway缓存刷新

soul网关源码分析之soul-gateway缓存刷新 目标 soul-gateway本地缓存刷新 总结 概述     上篇讲了soul-admin与soul-gateway通过websocket的方式进行数据的同步,本篇将详细介绍soul-gateway如果将内存中的缓存刷新的。 架构图     从架构图中能够看出,数据变更会通过pull模式或者push模式到soul-web模块,上篇文档提到了soul-web模块负责接收代理请求,各种filter,实际上sou

qq_31279701的博客 581

本地使用大模型:Ollama+open-webui+AnythingLLM(Windows+linux)

随着大模型的发展,大量的开源模型可以被直接使用。大模型的使用可以选择在云端或者在本地,如果本地存储空间尚可,而且模型需求不是很大的话,我们可以选择在本地部署一个大模型来使用。针对特定的任务需求,进一步在本地去微调我们的大模型。我在windows和linux上都尝试了一遍,这里记录一下过程。

wpqgt的博客 2165

Laravel 结合 jwt-auth 实现无状态 API 认证(实战解析)

本文详细解析了如何在Laravel框架中结合jwt-auth实现无状态API认证,包括JWT的优势、环境搭建、Token签发与刷新、API路由保护等实战内容。通过具体代码示例和优化技巧,帮助开发者高效解决跨域认证问题,提升系统安全性。

weixin_29315569的博客 210

Soul网关源码分析之soul-admin与soul-gateway使用Websocket数据同步

Soul网关源码分析之soul-admin与soul-gateway数据同步 目标 soul网关项目结构介绍 soul-admin和soul网关数据同步 总结 soul网关项目结构 从GitHub下载项目 从soul网关的github仓库下载soul项目,你也可以fork到你的GitHub仓库 git clone https://github.com/dromara/soul.git soul项目目录介绍 soul-admin:soul网关管理后台服务,提供了插

qq_31279701的博客 1019

SA8155 QNX显示框架与WFD配置实战:从黑屏排查到高可用设计

智能座舱中,车载显示系统的稳定性直接关系到驾驶安全。QNX作为高安全性的操作系统,在座舱仪表、ADAS等关键域中承担着确定性调度与隔离职责,其图形体系Screen与显示输出框架WFD协同工作,构成从应用渲染到面板点亮的完整链路。WFD配置涉及时序、通道映射与行为控制,任何参数偏差或加载异常都可能导致黑屏、花屏等故障。为保障系统可用性,需结合心跳监控、日志采集、通路重试与备份显示切换等策略,构建兼具快速感知与恢复能力的防御体系。本文以SA8155平台为例,深入拆解QNX显示框架的架构与WFD配置要点,结合一次

weixin_29165465的博客 203

soul网关源码分析之熔断插件-1

目标 soul网关集成并配置熔断插件 测试不通熔断参数的熔断结果 分析soul网关熔断插件的原理 总结 soul网关集成病配置熔断插件 ​ soul网关的hystrix插件是网关用来对流量进行熔断的核心实现,使用信号量的方式来处理请求 soul网关集成hystrix插件 <dependency> <groupId>org.dromara</groupId> <artifactId>s

qq_31279701的博客 298

密码学小白必看:三大顶级会议论文下载与阅读指南(附完整资源链接)

本文为密码学初学者提供了系统获取和阅读三大顶级会议(Crypto、Eurocrypt、Asiacrypt)论文的实战指南。详细介绍了通过IACR官方渠道、ePrint预印本等权威资源免费下载论文的方法,并分享了高效筛选、精读核心章节及构建个人知识体系的具体策略,帮助读者快速切入密码学研究前沿。

weixin_28363123的博客 390

soul源码分析(0)阅读源码准备与soul基础

soul源码分析(0)阅读源码的准备与预备知识 目标 fork代码 本地编译成功 启动网关 soul基础 fork代码 github fork到自己的repo,然后在本地: git clone https://github.com/evasnowind/soul cd soul git branch --set-upstream-to=origin/master 由于目前master分支在不断迭代、开发中,个人建议可以先拉取一个稳定的版本,方便阅读。 git fetch origin 2.2.1:

evasnowind的专栏 535

揭秘CAS:深入理解与应用解析

在并发编程中,Compare-And-Swap(CAS)机制作为一种无锁算法,凭借其高效性和避免线程阻塞的优势,受到广泛关注。CAS不仅在底层实现上有着重要地位,还在实际开发中发挥着关键作用。本文将从CAS的工作原理、在Java中的实现及其增强机制来回顾和加深理解一下CAS。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 85万+

Soul网关源码探秘《十九》 - RateLimiter 插件源码分析

前文探讨的 Hystrix 插件可以用来实现熔断降级。今天来研究可以实现限流的 RateLimiter 插件。 准备工作 启动soul-admin项目,并在后台页面开启divide和RateLimiter插件。 开启RateLimiter插件时需要配置redis信息。在本地起一个redis服务。 2. 在soul-admin中配置RateLimiter插件的选择器和规则。 选择器: 规则: 选择器的配置跟之前探讨过的插件都类似。规则配置中有两个差异化的参数。 capacity:是允许用户在一秒钟

rughru的博客 477

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

soul源码解读(十八)-- resilience4j插件原理分析

soul源码解读(十八)resilience4j插件使用 resilience4j resilience4j插件是网关用来对流量进行限流与熔断的可选选择之一。 resilience4j为网关熔断限流提供能力。 插件使用 1.启动 admin,打开 resilience4j 插件开关 2.在 bootstrap 项目的 pom 文件引入 resilience4j 插件的相关依赖,启动 bootstrap <!-- soul resilience4j plugin start--> <

可惜没如果的博客 855

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Soul源码解析(3)-Dubbo用户使用及divide插件源码分析

MM01-0116作业 Soul网关功能-Dubbo用户使用及divide插件源码分析 本次目标:体验Soul网关dubbo使用及divide插件分析 说明: dubbo插件是将http协议 转换成dubbo协议 的插件,也是网关实现dubbo泛化调用的关键; ubbo插件需要配合元数据才能实现dubbo的调用; apache dubbo 和 alibaba dubbo用户,都是使用该同一插件; 登录管理后台,找到插件管理,把dubbo插件状态改为开启; 在项目pom文件中引入以下依赖 <

qq_38314459的博客 273
上一篇: soul 源码分析 —— 插件解析之GlobalPlugin插件
下一篇: soul 源码分析 —— 插件解析之DividePlugin插件
cj271230
博客等级 码龄16年 1粉丝 14原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值