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

本次目标:体验Soul网关dubbo使用及divide插件分析

说明:

  • dubbo插件是将http协议 转换成dubbo协议 的插件,也是网关实现dubbo泛化调用的关键;
  • dubbo插件需要配合元数据才能实现dubbo的调用;
  • apache dubbo 和 alibaba dubbo用户,都是使用该同一插件;

登录管理后台,找到插件管理,把dubbo插件状态改为开启;

在这里插入图片描述

  • 在项目pom文件中引入以下依赖
 <!--if you use dubbo start this-->
   <dependency>
       <groupId>org.dromara</groupId>
       <artifactId>soul-spring-boot-starter-plugin-alibab-dubbo</artifactId>
       <version>2.2.1</version>
   </dependency>

   <dependency>
       <groupId>org.dromara</groupId>
       <artifactId>soul-spring-boot-starter-plugin-apache-dubbo</artifactId>
       <version>2.2.1</version>
   </dependency>
  • 因为要用到zookeeper作为注册中心,所以还需要在本地启动一个zookeeper服务

在这里插入图片描述

  • 在dubbo插件的配置中,配置如下:配置dubbo的注册中心
{"register":"zookeeper://localhost:2181"} or {"register":"nacos://localhost:8848"} 

在这里插入图片描述

  • 然后是在方法上添加@SoulDubboClient注解

在这里插入图片描述

启动服务之后,可以在 soul-admin -->元数据管理,进行查看;每一个dubbo接口方法,都会对应一条元数据。

在这里插入图片描述

通过postman用下面的地址访问

http://localhost:9195/dubbo/findById?id=9

在这里插入图片描述

divide插件源码分析

Plugins的链式处理核心类是:SoulWebHandler,从这里开始打断点调试:

//委托给链中的下一个
public Mono<Void> execute(final ServerWebExchange exchange) {
            return Mono.defer(() -> {
                if (this.index < plugins.size()) {
                    SoulPlugin plugin = plugins.get(this.index++);
                    Boolean skip = plugin.skip(exchange);
                    if (skip) {
                        return this.execute(exchange);
                    }
                    return plugin.execute(exchange, this);
                }
                return Mono.empty();
            });
        }

根据名字找到soul-plugin-divide模块,找到下面的DividePlugin类。DividePlugin继承AbstractSoulPlugin抽象类,AbstractSoulPlugin实现了SoulPlugin接口,接口定义如下:

public interface SoulPlugin {

   //处理Web请求并(可选地)委托给下一个插件
    Mono<Void> execute(ServerWebExchange exchange, SoulPluginChain chain);

    //此属性用于确定同一类型插件中的插件执行顺序
    int getOrder();

   //这是插件名称定义,您必须提供正确的名称。如果实现了AbstractSoulPlugin,这个属性就不用了
    default String named() {
        return "";
    }

    //是否跳过,如果返回true则不执行
    default Boolean skip(ServerWebExchange exchange) {
        return false;
    }

AbstractSoulPlugin类里面的execute()方法,如果匹配到了就执行相应的规则,否则继续筛选下一个插件数据和规则

public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        String pluginName = named();
    	//通过pluginName去缓存里面获取pluginData
        final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
        //如果pluginData不为空并且插件开启
    	if (pluginData != null && pluginData.getEnabled()) {
            //根据插件名称获取选择器
            final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
            //选择器为空时的处理
            if (CollectionUtils.isEmpty(selectors)) {
                return handleSelectorIsNull(pluginName, exchange, chain);
            }
            
            final SelectorData selectorData = matchSelector(exchange, selectors);
            if (Objects.isNull(selectorData)) {
                return handleSelectorIsNull(pluginName, exchange, chain);
            }
            //日志打印
            selectorLog(selectorData, pluginName);
            //获取配置规则
            final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
            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);
            }
            if (Objects.isNull(rule)) {
                return handleRuleIsNull(pluginName, exchange, chain);
            }
            ruleLog(rule, pluginName);
            return doExecute(exchange, chain, selectorData, rule);
        }
        return chain.execute(exchange);
    }

然后我们看一下实现类DividePlugin里面的doExecute()方法,如果匹配到了plugin配置信息,则执行对应方法:

protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
    	//获取context配置信息
        final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
        //判断soulContext不为空
    assert soulContext != null;
    //获取rule配置数据
        final DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class);
    //获取父级分发数据,如果为空,则抛出异常
        final List<DivideUpstream> upstreamList = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(selector.getId());
        if (CollectionUtils.isEmpty(upstreamList)) {
            log.error("divide upstream configuration error: {}", rule.toString());
            Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
            return WebFluxResultUtils.result(exchange, error);
        }
    //获取ip
        final String ip = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress();
        //获取父级入口负载策略
    DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip);
        if (Objects.isNull(divideUpstream)) {
            log.error("divide has no upstream");
            Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
            return WebFluxResultUtils.result(exchange, error);
        }
        // set the http url
        String domain = buildDomain(divideUpstream);
        String realURL = buildRealURL(domain, soulContext, exchange);
        exchange.getAttributes().put(Constants.HTTP_URL, realURL);
        // set the http timeout
        exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
        exchange.getAttributes().put(Constants.HTTP_RETRY, ruleHandle.getRetry());
        return chain.execute(exchange);
    }

总结

Soul是如何实现把http协议转为dubbo协议的呢?修改的配置数据是如何进行数据同步的呢?是如何实现插件的热插拔?转发是如何实现的?限流是如何实现的?敬请期待接下来的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值