Dubbo的Filter实战--整合Oval校验框架
前言:
其实很早之前就想写一篇关于oval和具体服务相整合的常见做法, 并以此作为一篇笔记. 趁现在项目中间空闲期, 刚好对dubbo的filter有一些了解. 因此想结合两者, 写一下既结合校验框架, 又能少侵入性的编程模式.
Dubbo的filter机制, 其实对标springmvc的interceptor, netty的iohandler, 甚至servlet体系的filter, 都是责任链模式的实现方式. 本文着重dubbo的filter和oval校验框架的组合, 其实完全可以借鉴/延伸过去, 因此本文有它的意义.
常见的Dubbo接口约定:
现在流行的做法, 两个服务之间的调用, 是不会把异常信息抛给对方, 而是内部把异常转化为特定的错误码, 并告知调用方.
常见的响应类模式被设计为泛型Result, 而真正返回的实体就是泛型对应的对象.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Getter @Setter @ToString public class TResult<T> { private boolean success = true ; private int errCode = 0 ; private String errMsg = "OK" ; private T value = null ; } |
当success为true时, 泛型对象value为真正的实体, 而success为false时, 则errCode/errMsg会具体描述各类错误情况, 比如参数不正确/状态不正确.
常见的实现方法:
服务端的接口具体的实现, 往往是这样的模样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | @Getter @Setter class EchoReq { @NotNull (message = "message字段不能为空" ) private String message; } public interface IEchoService { TResult<String> echo1(String name); TResult<String> echo2(EchoReq req); } // *) 需要设定@Guarded注解, 才能使函数参数的preconditions校验机制生效 @Guarded @Service ( "echoService" ) public class EchoServiceImpl implements IEchoService { @Override public TResult<String> echo1( @NotNull (message= "name字段不能为空" ) String name) { TResult<String> result = new TResult<String>(); return result; } @Override public TResult<String> echo2(EchoReq req) { TResult<String> result = new TResult<String>(); try { // *) 参数校验 Validator validator = new Validator(); List<ConstraintViolation> cvs = validator.validate(req); if ( cvs != null && cvs.size() > 0 ) { result.setSuccess( false ); result.setErrCode( 10001 ); result.setErrMsg( "参数不正确:" + cvs.get( 0 ).getMessage()); return result; } // *) 具体的业务代码 } catch (Throwable e) { result.setSuccess( false ); result.setErrCode( 10002 ); result.setErrMsg( "Internal Server Error:" ); return result; } return result; } } |
正如你所见的, 核心代码外围需要一个try/catch以支持异常到错误码的转换, 能否有个办法去掉这个try/catch.
同时Oval注解不光作用于Bean类的属性成员上, 还可以在作用于函数的参数上, 这样的话, try/catch就覆盖不及了.
来个题外话, 让oval支持preconditions, 需要一些额外的工作, 默认不开启. 可使用spring-aop来开启, 可具体参阅该文章.
类似这样的配置:
1 2 3 4 5 6 7 8 9 10 11 | < beans > < bean id="myService" class="MyServiceImpl" /> < bean id="ovalGuardInterceptor" class="net.sf.oval.guard.GuardInterceptor" /> < bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> < property name="proxyTargetClass" value="true" /> < property name="beanNames" value="*Service" /> < property name="interceptorNames">< list >< value >ovalGuardInterceptor</ value ></ list ></ property > </ bean > </ beans > |
引入filter:
我们引入OvalFilter, 具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public class OvalFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { Result result = invoker.invoke(invocation); if ( result.hasException() ) { TResult<Void> res = new TResult<Void>(); Throwable e = result.getException(); if ( e instanceof ConstraintsViolatedException) { // *) 参数不正确 res.setSuccess( false ); res.setErrCode( 10001 ); res.setErrMsg(e.getMessage()); } else { // *) 服务端内部错误 res.setSuccess( false ); res.setErrCode( 10002 ); res.setErrMsg( "Internal Server Error" ); } return new RpcResult(res); } return result; } } |
Dubbo的filter的引入, 以及配置, 可以具体参阅文章:
1. Dubbo透传traceId/logid的一种思路
2. Dubbo的Filter链梳理---分组可见和顺序调整
测试的结果, 符合预期, OvalFilter成功地把Dubbo的service抛出的ConstraintsViolatedException捕获, 并成功转化为参数校验失败的错误信息返回. 这样的好处, 可以让dubbo具体的service实现类, 减少异常的处理, 使得代码简洁, 可读性更强.
以上面的样例代码为例, 我们可以简化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @Guarded @Service ( "echoService" ) public class EchoServiceImpl implements IEchoService { @Override public TResult<String> echo1( @NotNull (message= "name字段不能为空" ) String name) { TResult<String> result = new TResult<String>(); return result; } @Override public TResult<String> echo2(EchoReq req) { TResult<String> result = new TResult<String>(); // *) 参数校验 Validator validator = new Validator(); List<ConstraintViolation> cvs = validator.validate(req); if ( cvs != null && cvs.size() > 0 ) { throw new ConstraintsViolatedException(cvs); } // *) 具体的业务代码 return result; } } |
总结:
Dubbo服务如何处理参数校验这块, 不同的人/公司, 都有自己的偏好. 本文讲述了利用Oval框架来校验参数, 同时利用dubbo强大的自定义filter机制, 把校验参数异常隐藏, 并返回更友好的提示信息. 同时使服务的代码更加简洁, 可读性更强.
在整理这块时, 感觉Oval的preconditions支持水更深, 希望自己有机会对这块能够深入研究下.
posted on 2018-06-28 15:40 mumuxinfei 阅读(1073) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构