10人参与 • 2025-10-20 • Asp.net
filter是dubbo框架中实现拦截逻辑的核心接口,作用于服务消费者和提供者的作业链路,支持在方法调用前后插入自定义逻辑。如参数校验、异常处理、日志记录等。
dubbo通过spi扩展机制动态加载filter实现类,构建链式调用结构,每个filter通过invoke方案传递调用上下文,最终执行目标方法。
provider端filter链在服务暴露时通过filterchainbuilder#buildinvokerchain方法构建,基于spi配置按优先级排序,形成多层拦截逻辑。
filter实现类需要在meta-inf/dubbo/internal/org.apache.dubbo.rpc.filter文件中声明,并通过@activate注解配置激活条件(如服务端/消费端)
filter链在服务初始化阶段动态生成,通过extensionloader加载所有激活的filter实例,并按顺序包装成调用链。
| filter名称 | 功能描述 | 适用端 |
|---|---|---|
| exceptionfilter | 统一处理服务端异常,将非受检异常封装为runtimeexception返回客户端 | provider |
| validationfilter | 基于jsr303标准校验接口参数合法性 | both |
| accesslogfilter | 记录服务调用日志,指定输出到指定文件 | provider |
| timeoutfilter | 监控方法执行超时,触发超时中断逻辑 | provider |
| genericfilter | 处理泛化调用的序列化与反序列化 | both |
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;
}
}
在resources/meta-inf/dubbo目录下创建配置文件org.apache.dubbo.rpc.filter,添加自定义filter类路径:
consumer=com.doudou.demo.filter.customfilter
dubbo的validationfilter是基于jsr303标准实现的参数校验组件,主要用于服务消费者和服务提供者两端,确保接口调用时参数的合法性。
作用机制
@activate注解激活,默认作用于消费者和服务者两端,执行顺序为10000。依赖配置
需要引入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>
@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()));
}
}
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));
}
@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;
}
@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);
}
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论