当前位置: 代码网 > it编程>编程语言>Asp.net > dubbo参数校验ValidationFilter使用与说明

dubbo参数校验ValidationFilter使用与说明

2025年10月20日 Asp.net 我要评论
org.apache.dubbo.rpc.filter核心功能拦截rpc调用流程filter是dubbo框架中实现拦截逻辑的核心接口,作用于服务消费者和提供者的作业链路,支持在方法调用前后插入自定义逻

org.apache.dubbo.rpc.filter

核心功能

  • 拦截rpc调用流程

filter是dubbo框架中实现拦截逻辑的核心接口,作用于服务消费者和提供者的作业链路,支持在方法调用前后插入自定义逻辑。如参数校验、异常处理、日志记录等。

  • 扩展性机制

dubbo通过spi扩展机制动态加载filter实现类,构建链式调用结构,每个filter通过invoke方案传递调用上下文,最终执行目标方法。

实现机制

  • 责任链模式

provider端filter链在服务暴露时通过filterchainbuilder#buildinvokerchain方法构建,基于spi配置按优先级排序,形成多层拦截逻辑。

  • spi加载规则

filter实现类需要在meta-inf/dubbo/internal/org.apache.dubbo.rpc.filter文件中声明,并通过@activate注解配置激活条件(如服务端/消费端)

  • 动态加载

filter链在服务初始化阶段动态生成,通过extensionloader加载所有激活的filter实例,并按顺序包装成调用链。

常见内置filter实现

filter名称功能描述适用端
exceptionfilter统一处理服务端异常,将非受检异常封装为runtimeexception返回客户端provider
validationfilter基于jsr303标准校验接口参数合法性both
accesslogfilter记录服务调用日志,指定输出到指定文件provider
timeoutfilter监控方法执行超时,触发超时中断逻辑provider
genericfilter处理泛化调用的序列化与反序列化both

自定义filter实现步骤

  • 实现filter接口
import com.alibaba.fastjson2.json;
import org.apache.dubbo.common.constants.commonconstants;
import org.apache.dubbo.common.extension.activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.logger;
import org.slf4j.loggerfactory;

// 使用@activate注解指定filter生效场景
// order属性控制执行顺序,值越小,优先级越高
@activate(group = {commonconstants.consumer, commonconstants.provider}, order = 10001)
public class customfilter implements filter {
    private logger logger = loggerfactory.getlogger(customfilter.class);
    @override
    public result invoke(invoker<?> invoker, invocation invocation) throws rpcexception {
        logger.info("invoker invoked method {} {} {} {}",
                invocation.getmethodname(),
                json.tojsonstring(invocation.getobjectattachments()),
                invocation.getattributes(),
                json.tojsonstring(invocation.getarguments()));
        result result = invoker.invoke(invocation);
        logger.info("invoker invoked result {}", json.tojsonstring(result));
        return result;
    }
}
  • ‌声明spi扩展‌

在resources/meta-inf/dubbo目录下创建配置文件org.apache.dubbo.rpc.filter,添加自定义filter类路径:

consumer=com.doudou.demo.filter.customfilter

validationfilter

dubbo的validationfilter是基于jsr303标准实现的参数校验组件,主要用于服务消费者和服务提供者两端,确保接口调用时参数的合法性。

核心特性

作用机制

  • 通过@activate注解激活,默认作用于消费者和服务者两端,执行顺序为10000。
  • 在请求处理前拦截参数,利用jsr303标准的注解进行校验,校验失败时抛出异常中断流程。

依赖配置

需要引入validation-apihibernate-validator依赖包

 <!-- bean validation api -->
<dependency>
    <groupid>javax.validation</groupid>
    <artifactid>validation-api</artifactid>
    <version>2.0.1.final</version>
</dependency>
<!-- hibernate validator实现 -->
<dependency>
    <groupid>org.hibernate.validator</groupid>
    <artifactid>hibernate-validator</artifactid>
    <version>6.2.5.final</version>
</dependency>
<dependency>
    <groupid>org.glassfish</groupid>
    <artifactid>jakarta.el</artifactid> <!-- 适配el表达式 -->
    <version>5.0.0-m1</version>
</dependency>

使用

api

@setter
@getter
public class userdto implements serializable {
    @notblank(message = "用户名不能为空")
    private string username;

    @min(value = 18, message = "年龄必须大于18岁")
    private integer age;

    @email(message = "邮箱格式不合法")
    private string email;
}
public class baseresult<t> {
    // 处理是否正确结束
    private boolean success;
    // 异常编码
    private integer errorcode;
    // 异常描述
    private string errormsg;
    // dubbo接口返回的结果
    private t data;
}    
public interface userservice {
    baseresult<string> registeruser(userdto userdto);
}

服务提供者

@dubboservice(validation = "true")
public class userserviceimpl implements userservice {

    @override
    public baseresult<string> registeruser(userdto userdto) {
        return baseresult.success("用户注册成功:" + userdto.getusername());
    }
}
public class parameterverificationresultfilter implements filter {
    private logger logger = loggerfactory.getlogger(parameterverificationresultfilter.class);

    @override
    public result invoke(invoker<?> invoker, invocation invocation) throws rpcexception {
        result result = invoker.invoke(invocation);
        // 处理出现异常
        if (result.hasexception()) {
            throwable exception = result.getexception();
            // 是由参数校验失败抛出的异常
            if (exception instanceof constraintviolationexception) {
                list<string> errors = ((constraintviolationexception) exception).getconstraintviolations().stream()
                        .map(v -> v.getpropertypath() + ": " + v.getmessage())
                        .collect(collectors.tolist());
                logger.info("---------------2---------------");
                logger.error(errors.tostring());
                logger.info("---------------3---------------");
                // 将错误信息封装到返回结果中
                return asyncrpcresult.newdefaultasyncresult(baseresult.fail(400, errors.tostring()), invocation);
            }
        }
        return result;
    }
}

meta-inf/dubbo/org.apache.dubbo.rpc.filter

# 参数校验过滤器
validation=org.apache.dubbo.validation.filter.validationfilter
# 校验结果处理过滤器
parameterverification=com.doudou.filter.parameterverificationresultfilter

application.yml

dubbo:
	provider:
		filter: validation,parameterverification

服务消费方

@restcontroller
public class userservicecontroller {
    @dubboreference(validation = "true")
    private userservice userservice;

    @postmapping("/test")
    public baseresult<string> test(@requestbody userdto userdto) {
        return userservice.registeruser(userdto);
    }
}
@restcontrolleradvice
public class globalexceptionhandler {

    // 处理rpcexception异常
    @exceptionhandler(rpcexception.class)
    public responseentity<baseresult> handlevalidationexception(rpcexception rpcexception) {
        return responseentity.badrequest().body(baseresult.fail(403, rpcexception.getlocalizedmessage()));
    }
}

源码解析

org.apache.dubbo.validation.filter.validationfilter

public result invoke(invoker<?> invoker, invocation invocation) throws rpcexception {
   // 判断是否需要进行参数验证
    if (needvalidate(invoker.geturl(), invocation.getmethodname())) {
        try {
            // 通过url中的validation属性值获取验证器
            validator validator = validation.getvalidator(invoker.geturl());
            if (validator != null) {
                // 获取到验证器时,进行参数验证
                validator.validate(
                        invocation.getmethodname(), invocation.getparametertypes(), invocation.getarguments());
            }
        } catch (rpcexception e) {
            // rpcexception 异常直接抛出
            throw e;
        } catch (throwable t) {
            // 非rpcexception,封装到结果中返回
            return asyncrpcresult.newdefaultasyncresult(t, invocation);
        }
    }
    // 执行下一个过滤器的处理
    return invoker.invoke(invocation);
}

 /**
  * 是否需要进行参数验证
  */
 private boolean needvalidate(url url, string methodname) {
     return validation != null
             && !methodname.startswith("$")
             && configutils.isnotempty(url.getmethodparameter(methodname, validation_key))
             && !"false".equalsignorecase(url.getparameter(validation_key));
 }

org.apache.dubbo.validation.support.abstractvalidation

@override
public validator getvalidator(url url) {
    // 使用url作为存储验证器map集合的的key
    string key = url.tofullstring();
    // 从容器中获取验证器
    validator validator = validators.get(key);
    // 判断验证器是否已经存在
    if (validator == null) {
        // 如果不存在,则创建
        validators.put(key, createvalidator(url));
        validator = validators.get(key);
    }
    return validator;
}

org.apache.dubbo.validation.support.jvalidation.jvalidation

@activate(onclass = "javax.validation.validation")
public class jvalidation extends abstractvalidation {

    /**
     * return new instance of {@link jvalidator}
     * @param url valid url instance
     * @return instance of jvalidator
     */
    @override
    protected validator createvalidator(url url) {
        // 创建一个dubbo框架默认的校验器
        return new jvalidator(url);
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com