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

GlobalPlugin插件

GlobalPlugin插件是soul所有插件执行前,最先执行的一个插件。

作用是构建一个soul的上下文环境。

SoulContext

soul的上下文环境,由GlobalPlugin插件来构建

public class SoulContext implements Serializable {

    /**
     * is module data.
     */
    private String module;

    /**
     * is method name .
     */
    private String method;

    /**
     * is rpcType data. now we only support "http","dubbo","springCloud","sofa".
     */
    private String rpcType;

    /**
     * httpMethod now we only support "get","post" .
     */
    private String httpMethod;

    /**
     * this is sign .
     */
    private String sign;

    /**
     * timestamp .
     */
    private String timestamp;

    /**
     * appKey .
     */
    private String appKey;

    /**
     * path.
     */
    private String path;
    
    /**
     * the contextPath.
     */
    private String contextPath;

    /**
     * realUrl.
     */
    private String realUrl;

    /**
     * this is dubbo params.
     */
    private String dubboParams;

    /**
     * startDateTime.
     */
    private LocalDateTime startDateTime;
    

}

说明如下:

  • module:模块名,也就是当前的contextPath、当前执行的选择器名

  • method:方法名,contextPath之后的路径名

  • rpcType:远程调用类型,目前支持:http、dubbo、springCloud、sofa

  • httpMethod:http请求方法,目前支持:get和post

  • sign:请求头携带的签名

  • timestamp:请求时的时间戳

  • appKey:请求头携带的appKey

  • path:请求的真实路径,比如:http/order/findById(http://localhost:9195/http/order/findById?id=9)

  • contextPath:请求的根路径

  • realUrl:请求的真实路径

  • dubboParams:请求的dubbo参数

  • startDateTime:请求在网关中的开始执行时间

GlobalPlugin处理解析

请求进入GlobalPlugin插件,执行execute方法。

该方法的作用是构建soulContext上下文

    @Override
    public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        final ServerHttpRequest request = exchange.getRequest();
        final HttpHeaders headers = request.getHeaders();
        // 获取请求头“Upgrade”
        final String upgrade = headers.getFirst("Upgrade");
        // 定义soul上下文对象
        SoulContext soulContext;
        // 请求头不包含“Upgrade” 或者 不包含“websocket”
        if (StringUtils.isBlank(upgrade) || !"websocket".equals(upgrade)) {
            // 调用DefaultSoulContextBuilder的 build方法来构建上下文对象
            soulContext = builder.build(exchange);
        } else {
            final MultiValueMap<String, String> queryParams = request.getQueryParams();
            soulContext = transformMap(queryParams);
        }
        exchange.getAttributes().put(Constants.CONTEXT, soulContext);
        return chain.execute(exchange);
    }

如果请求头不包含“Upgrade” 或者 不包含“websocket”,执行 builder.build(exchange)方法,即调用DefaultSoulContextBuilderbuild方法来构建上下文对象

    @Override
    public SoulContext build(final ServerWebExchange exchange) {
        final ServerHttpRequest request = exchange.getRequest();
        // 获取实际的请求路径
        String path = request.getURI().getPath();
        // 通过缓存,根据实际请求路径获取元数据信息
        MetaData metaData = MetaDataCache.getInstance().obtain(path);
        // 获取的元数据不为空,并且已启用元数据
        if (Objects.nonNull(metaData) && metaData.getEnabled()) {
            // 将“metaData” 放到当前exchange的请求属性中
            exchange.getAttributes().put(Constants.META_DATA, metaData);
        }
        return transform(request, metaData);
    }

通过build方法,先判断是否有元数据信息,如果有,将“metaData” 放到当前exchange的请求属性中,接着构建soulContext的上下文属性:

private SoulContext transform(final ServerHttpRequest request, final MetaData metaData) {
        final String appKey = request.getHeaders().getFirst(Constants.APP_KEY);
        final String sign = request.getHeaders().getFirst(Constants.SIGN);
        final String timestamp = request.getHeaders().getFirst(Constants.TIMESTAMP);
        SoulContext soulContext = new SoulContext();
        String path = request.getURI().getPath();
        // 设置真实请求路径
        soulContext.setPath(path);
        // 存在“metaData”数据,进行soulContext上下文赋值处理
        if (Objects.nonNull(metaData) && metaData.getEnabled()) {
            if (RpcTypeEnum.SPRING_CLOUD.getName().equals(metaData.getRpcType())) {
                setSoulContextByHttp(soulContext, path);
                soulContext.setRpcType(metaData.getRpcType());
            } else if (RpcTypeEnum.DUBBO.getName().equals(metaData.getRpcType())) {
                setSoulContextByDubbo(soulContext, metaData);
            } else if (RpcTypeEnum.SOFA.getName().equals(metaData.getRpcType())) {
                setSoulContextBySofa(soulContext, metaData);
            } else if (RpcTypeEnum.TARS.getName().equals(metaData.getRpcType())) {
                setSoulContextByTars(soulContext, metaData);
            } else {
                setSoulContextByHttp(soulContext, path);
                soulContext.setRpcType(RpcTypeEnum.HTTP.getName());
            }
        } else {

            // 如果没有meata信息,一般的http请求(普通的springboot微服务应用)
            setSoulContextByHttp(soulContext, path);
            // 设置rpc类型为:http
            soulContext.setRpcType(RpcTypeEnum.HTTP.getName());
        }
        soulContext.setAppKey(appKey);
        soulContext.setSign(sign);
        soulContext.setTimestamp(timestamp);
        soulContext.setStartDateTime(LocalDateTime.now());
        Optional.ofNullable(request.getMethod()).ifPresent(httpMethod -> soulContext.setHttpMethod(httpMethod.name()));
        return soulContext;
    }

transform方法就是为soulContext上下文各属性赋值。比较注意的点就是对contextPath和realUrl的操作。

private void setSoulContextByHttp(final SoulContext soulContext, final String path) {
        String contextPath = "/";
        String[] splitList = StringUtils.split(path, "/");
        /**
         * 比如请求:http://localhost:9195/http/order/findById?id=9
         * path:/http/order/findById
         * contextPath:获取真实路径的第一个,为:http
         */

        if (splitList.length != 0) {
            contextPath = contextPath.concat(splitList[0]);
        }
        // realUrl:设置contextPath之后的值,为:order/findById
        String realUrl = path.substring(contextPath.length());
        soulContext.setContextPath(contextPath);
        soulContext.setModule(contextPath);
        soulContext.setMethod(realUrl);
        soulContext.setRealUrl(realUrl);
    }

比如请求:http://localhost:9195/http/order/findById?id=9

  • path:/http/order/findById
  • contextPath:获取真实路径的第一个,为:http
  • realUrl:order/findById

赋值完soulContext之后,接着回到GlobalPlugin的execute方法

exchange.getAttributes().put(Constants.CONTEXT, soulContext);
return chain.execute(exchange);

把soulContext放到exchange的请求属性中,完成GlobalPlugin插件的处理,接着执行插件链中的下一个插件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值