首页 > 其他分享 >Dubbo RPC基于Filter的自定义参数校验

Dubbo RPC基于Filter的自定义参数校验

时间:2022-11-30 18:22:33浏览次数:95  
标签:Dubbo 拦截器 自定义 dubbo 校验 Filter rpc 参数 filter

在web应用中,我们经常使用注解的方式来校验参数,使得业务开发不用过分关注参数校验的逻辑
但是 在现有的微服务架构中,常常只是作为一个服务提供rpc 服务的方式,那是不是还是退步回繁琐的参数校验 不能统一处理了

转载请注明出处 https://www.cnblogs.com/majianming/p/16938621.html

背景

项目使用了dubbo 作为rpc治理的框架,所以仅对于这种方式的调用进行说明

本文基于Dubbo 2.6, 在2.7之后,dubbo成为Apache顶级项目,包名有所变化

需求

  1. 能提供全局的参数校验
  2. 能兼容现有的没有办法实现参数校验的接口(有一些旧接口 使用了实体直接返回 没有办法返回错误信息)

解决思路

dubbo 提供了Dubbo SPI机制来拓展拦截器 从拦截器可以获得调用方法以及参数信息

虽然dubbo 也同时提供了验证拓展 ,但是对于验证的结果,是直接抛出rpc 错误的形式,如果要自定义返回的话 还是使用拦截器处理相应的异常,还不如直接用spi来实现一个自定义的拦截器方便

实现

首先可以了解一下Dubbo 的SPI 与Java 的SPI 相比拓展了一些功能

声明SPI

  1. 需要在上建立一个拦截器实现,我们这里新建一个类ParamValidationFilter 实现com.alibaba.dubbo.rpc.Filter 接口

  2. 然后需要定义SPI的服务文件
    路径为${classPath}/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter

    对于我们常见的spring boot 项目 等于resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
    内容为(这里我们后面再讲内容的意义)

    param_validation_filter=xyz.ewis.app.filter.ParamValidationFilter
    

最终的效果是

src
 |-main
    |-java
        |-xyz
            |-ewis
                |-app
                    |-app
                        |-ParamValidationFilter.java
    |-resources
        |-META-INF
            |-dubbo
                |-com.alibaba.dubbo.rpc.Filter (纯文本文件,内容为:param_validation_filter=xyz.ewis.app.filter.ParamValidationFilter)

实现拦截器

@Slf4j
public class ParamValidationFilter implements Filter {
    private static final Validator validator;

    static {
        try {
            validator = Validation.buildDefaultValidatorFactory().getValidator();
        } catch (Exception e) {
            log.error("can not init validator", e);
            throw e;
        }
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        try {
            Method declaredMethod = invoker.getInterface()
                    .getDeclaredMethod(invocation.getMethodName(), invocation.getParameterTypes());
            Class<?> returnType = declaredMethod.getReturnType();
            // 因为我们要将错误信息返回 在这里校验了特定返回值情况 如果不是指定的返回值 就不校验了
            if (!ResultDTO.class.equals(returnType)) {
                return invoker.invoke(invocation);
            }
            Annotation[][] parameterAnnotations = declaredMethod.getParameterAnnotations();
            for (int i = 0; i < parameterAnnotations.length; i++) {
                Annotation[] parameterAnnotation = parameterAnnotations[i];
                // 遍历所有的参数 如果有javax.validation的注解才校验
                if (Arrays.stream(parameterAnnotation).noneMatch(pa -> Valid.class.equals(pa.annotationType()))) {
                    continue;
                }
                Object argument = invocation.getArguments()[i];
                // 参数是null 的情况 并且有javax.validation.constraints.NotNull 那么说明参数错误
            
                if (Objects.isNull(argument)) {
                    if (Arrays.stream(parameterAnnotation).anyMatch(pa -> NotNull.class.equals(pa.annotationType()))) {
                        return
                                new RpcResult(
                                        ResultDTO.fail(StateCode.ILLEGAL_ARGS, String.format("第%s 个参数不能为空", i + 1))
                                );
                    }
                    continue;
                }
                // 校验参数
                Set<ConstraintViolation<Object>> validate = validator.validate(argument);
                if (!validate.isEmpty()) {
                    // 如果有多个参数错误 也仅返回第一个参数错误信息 也可以改成多个都返回
                    ConstraintViolation<Object> objectConstraintViolation = CollectionUtils.get(validate, 0);
                    String message = objectConstraintViolation.getMessage();
                    return new RpcResult(ResultDTO.fail(StateCode.ILLEGAL_ARGS, message));
                }
            }
        } catch (
                NoSuchMethodException ignored) {
                    
        }
        // 没有检查到需要校验 或者 没有校验出错误 则调用业务逻辑
        return invoker.invoke(invocation);
    }
}

使用拦截器

参考官方的文件调用拦截扩展可以知道 可以配置为

<!-- 消费方调用过程拦截 -->
<dubbo:reference filter="param_validation_filter" />
<!-- 消费方调用过程缺省拦截器,将拦截所有reference -->
<dubbo:consumer filter="param_validation_filter"/>
<!-- 提供方调用过程拦截 -->
<dubbo:service filter="param_validation_filter" />
<!-- 提供方调用过程缺省拦截器,将拦截所有service -->
<dubbo:provider filter="param_validation_filter"/>

这里的param_validation_filter 实际上就是我们上面提到的META-INF/dubbo/com.alibaba.dubbo.rpc.Filter 中定义param_validation_filter=xyz.ewis.app.filter.ParamValidationFilter,说明调用过程要经过我们定义的xyz.ewis.app.filter.ParamValidationFilter拦截器

考虑到我们是使用api二方包在项目间使用其他项目的服务,
首先推动消费方添加filter 参数比较麻烦,重要的是在提供方修改api校验定义后,需要消费方更新提供api包,这对于众多的微服务来说,是无法接受的
所以我们还是使用了提供方提供拦截这种方式,同时我们目前逐步改成参数校验的模式,在切换过程中,先对指定服务生效,所以我们这里仅使用 提供方调用过程拦截 即

<!-- 提供方调用过程拦截 -->
<dubbo:service filter="param_validation_filter" />

转载请注明出处 https://www.cnblogs.com/majianming/p/16938621.html

标签:Dubbo,拦截器,自定义,dubbo,校验,Filter,rpc,参数,filter
From: https://www.cnblogs.com/majianming/p/16938621.html

相关文章

  • Spring Boot中使用Filter过滤器
    Filter过滤器一、引入在和管理员有关的Controller中,接口都需要判断当前用户是否为管理员,如果是管理员,则可以操作目录;如果不是管理员,则不能操作;这一连串的身份验证代码都......
  • DevExpress表格控件的单元格设置自定义编辑器
    RepositoryItememptyRepositoryItem=newRepositoryItem();RepositoryItemCheckEditcheckEdit=newRepositoryItemCheckEdit();RepositoryItemTextEdittextEdit=......
  • Dubbo -介绍以及基本使用(xml方式与properties方式)
    Dubbo介绍一个分布式、高性能、透明化的RPC服务框架。提供服务自动注册、自动发现等高效服务治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载......
  • Dubbo -注解方式和Api方式
    注解方式服务端<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema......
  • 自定义JetBrains的IDE界面缩放比例
    今天双11的时候,将我的换了一个27寸的4k分辨率的显示器,经过几周的使用,基本上已经适应了4k分辨率下的175%的缩放比率,但是Jetbrains的几个IDE使用新的UI的时候,在这个分辨率下......
  • 直播平台源代码,el-button自定义图片显示
    直播平台源代码,el-button自定义图片显示1在按钮处自定义icon          <el-button@click="to_devops(scope.row.pr_url)">       ......
  • 实践案例:平安健康的 Dubbo3 迁移历程总结
    本篇是ApacheDubbo的实践案例。感兴趣的朋友可以访问官网了解更多详情,或搜索关注官方微信公众号ApacheDubbo跟进最新动态。1背景我们公司从15年开始就使⽤dubb......
  • 【自定义控件】MyPanelParent MyParent
    代码MyPanelParent.csusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows......
  • day27-过滤器Filter02
    Filter过滤器025.Filter过滤器生命周期Filter生命周期图解验证-Tomcat来创建Filter实例,只会创建一个实例packagecom.filter;importjavax.servlet.*;importj......
  • Image Processing and Analysis_8_Edge Detection:The Design and Use of Steerable Fi
    此主要讨论图像处理与分析。虽然计算机视觉部分的有些内容比如特征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以及它们的出处,没有把它们纳入到图像......