欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > dubbo 参数校验-ValidationFilter

dubbo 参数校验-ValidationFilter

2025/5/6 2:53:37 来源:https://blog.csdn.net/zzw_17600691357/article/details/147704511  浏览:    关键词:dubbo 参数校验-ValidationFilter

org.apache.dubbo.rpc.Filter

核心功能

  1. 拦截RPC调用流程
    Filter是Dubbo框架中实现拦截逻辑的核心接口,作用于服务消费者和提供者的作业链路,支持在方法调用前后插入自定义逻辑。如参数校验、异常处理、日志记录等。
  2. 扩展性机制
    Dubbo通过SPI扩展机制动态加载Filter实现类,构建链式调用结构,每个Filter通过Invoke方案传递调用上下文,最终执行目标方法。

实现机制

  1. 责任链模式
    Provider端Filter链在服务暴露时通过FilterChainBuilder#buildInvokerChain方法构建,基于SPI配置按优先级排序,形成多层拦截逻辑。
  2. SPI加载规则
    Filter实现类需要在META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter文件中声明,并通过@Activate注解配置激活条件(如服务端/消费端)
  3. 动态加载
    Filter链在服务初始化阶段动态生成,通过ExtensionLoader加载所有激活的Filter实例,并按顺序包装成调用链。

常见内置Filter实现

Filter名称功能描述适用端
ExceptionFilter统一处理服务端异常,将非受检异常封装为RuntimeException返回客户端Provider
ValidationFilter基于JSR303标准校验接口参数合法性Both
AccessLogFilter记录服务调用日志,指定输出到指定文件Provider
TimeoutFilter监控方法执行超时,触发超时中断逻辑Provider
GenericFilter处理泛化调用的序列化与反序列化Both

自定义Filter实现步骤

  1. 实现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);@Overridepublic 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;}
}
  1. ‌声明SPI扩展‌
    在resources/META-INF/dubbo目录下创建配置文件org.apache.dubbo.rpc.Filter,添加自定义Filter类路径:
    consumer=com.doudou.demo.filter.CustomFilter

ValidationFilter

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

核心特性

  1. 作用机制
    • 通过@Activate注解激活,默认作用于消费者和服务者两端,执行顺序为10000。
    • 在请求处理前拦截参数,利用JSR303标准的注解进行校验,校验失败时抛出异常中断流程。
  2. 依赖配置
    • 需要引入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 {@Overridepublic BaseResult<String> registerUser(UserDTO userDTO) {return BaseResult.success("用户注册成功:" + userDTO.getUsername());}
}
public class ParameterVerificationResultFilter implements Filter {private Logger logger = LoggerFactory.getLogger(ParameterVerificationResultFilter.class);@Overridepublic 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集合的的keyString 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*/@Overrideprotected Validator createValidator(URL url) {// 创建一个Dubbo框架默认的校验器return new JValidator(url);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词