Soul源码阅读 插件加载解析【第十二天】

Soul中各个模块是按照插件进行加载的,插件有对应的优先级,会按照优先级排序然后顺序进行执行对应的插件进行处理请求。今天就来探究下插件是如何进行加载的以及插件是如何进行调用的。

SoulConfiguration配置了SoulWebHandler,使用ObjectProvider加载插件列表,并按照order字段进行排序【后面的插件执行顺序是按照这个来的】

SoulWebHandler主要是用来接收前端发过来的请求,然后使用插件列表中的插件对进来的请求进行处理,处理使用了handle方法,handle方法会在DefaultSoulPluginChain的构造器中传入插件列表,其中,DefaultSoulPluginChain实现了SoulPluginChain接口,方便插件调用下一个插件,根据skip方法判断是否是需要跳过的【即非当前插件类型的请求不进行执行,直到找到对应的插件进行调用返回】

插件接口SoulPlugin,包含了执行,顺序,名称,是否需要跳过四个需要实现的方法
AbstractSoulPlugin实现了执行的方法【通用的执行方法】

插件链条的发起的地方在GlobalPlugin,根据传进来的ServerWebExchange获取必要的信息,构造SoulContext,SoulContext很关键,下面所有的插件都会用到。

比如DividePlugin

 /**
     *
     * @param exchange exchange the current server exchange {@linkplain ServerWebExchange} 请求的信息,以及GlobalPlugin塞进来的SoulContext
     * @param chain    chain the current chain  {@linkplain ServerWebExchange} 调用链路,所有的加载的插件
     * @param selector selector    {@linkplain SelectorData} 选择器
     * @param rule     rule    {@linkplain RuleData} 规则
     * @return
     */
    @Override
    protected Mono doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
        final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
        assert soulContext != null;
        // 规则
        final DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class);
        // 获取缓存的调用的url列表信息
        final List 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();
        // 负载均衡选一个调用的url
        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);
    }

WebClientPlugin根据拼装的信息执行调用

@Override
    public Mono execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
        assert soulContext != null;
        String urlPath = exchange.getAttribute(Constants.HTTP_URL);
        if (StringUtils.isEmpty(urlPath)) {
            Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
            return WebFluxResultUtils.result(exchange, error);
        }
        long timeout = (long) Optional.ofNullable(exchange.getAttribute(Constants.HTTP_TIME_OUT)).orElse(3000L);
        int retryTimes = (int) Optional.ofNullable(exchange.getAttribute(Constants.HTTP_RETRY)).orElse(0);
        log.info("The request urlPath is {}, retryTimes is {}", urlPath, retryTimes);
        HttpMethod method = HttpMethod.valueOf(exchange.getRequest().getMethodValue());
        WebClient.RequestBodySpec requestBodySpec = webClient.method(method).uri(urlPath);
        return handleRequestBody(requestBodySpec, exchange, timeout, retryTimes, chain);
    }

查看下PluginEnum,RESPONSE是在最后一个,也就是返回结果的地方。
最后是调用WebClientResponsePlugin返回执行结果

@Override
    public Mono execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        return chain.execute(exchange).then(Mono.defer(() -> {
            ServerHttpResponse response = exchange.getResponse();
            ClientResponse clientResponse = exchange.getAttribute(Constants.CLIENT_RESPONSE_ATTR);
            if (Objects.isNull(clientResponse)
                    || response.getStatusCode() == HttpStatus.BAD_GATEWAY
                    || response.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
                Object error = SoulResultWrap.error(SoulResultEnum.SERVICE_RESULT_ERROR.getCode(), SoulResultEnum.SERVICE_RESULT_ERROR.getMsg(), null);
                return WebFluxResultUtils.result(exchange, error);
            }
            if (response.getStatusCode() == HttpStatus.GATEWAY_TIMEOUT) {
                Object error = SoulResultWrap.error(SoulResultEnum.SERVICE_TIMEOUT.getCode(), SoulResultEnum.SERVICE_TIMEOUT.getMsg(), null);
                return WebFluxResultUtils.result(exchange, error);
            }
            response.setStatusCode(clientResponse.statusCode());
            response.getCookies().putAll(clientResponse.cookies());
            response.getHeaders().putAll(clientResponse.headers().asHttpHeaders());
            return response.writeWith(clientResponse.body(BodyExtractors.toDataBuffers()));
        }));
    }

你可能感兴趣的:(Soul源码阅读 插件加载解析【第十二天】)