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-api
和hibernate-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); } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论