前言:
  其实很早之前就想写一篇关于oval和具体服务相整合的常见做法, 并以此作为一篇笔记. 趁现在项目中间空闲期, 刚好对dubbo的filter有一些了解. 因此想结合两者, 写一下既结合校验框架, 又能少侵入性的编程模式.
  Dubbo的filter机制, 其实对标springmvc的interceptor, netty的iohandler, 甚至servlet体系的filter, 都是责任链模式的实现方式. 本文着重dubbo的filter和oval校验框架的组合, 其实完全可以借鉴/延伸过去, 因此本文有它的意义.

常见的Dubbo接口约定:
  现在流行的做法, 两个服务之间的调用, 是不会把异常信息抛给对方, 而是内部把异常转化为特定的错误码, 并告知调用方.
  常见的响应类模式被设计为泛型Result, 而真正返回的实体就是泛型对应的对象.

@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会具体描述各类错误情况, 比如参数不正确/状态不正确.

常见的实现方法:
  服务端的接口具体的实现, 往往是这样的模样:

@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来开启, 可具体参阅该文章.

  类似这样的配置:

<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, 具体代码如下:

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实现类, 减少异常的处理, 使得代码简洁, 可读性更强.

  以上面的样例代码为例, 我们可以简化如下:

@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支持水更深, 希望自己有机会对这块能够深入研究下.

Dubbo的Filter实战--整合Oval校验框架的更多相关文章

  1. springMVC:校验框架:多规则校验,嵌套校验,分组校验;ssm整合技术

    知识点梳理 课堂讲义 学习目标 能够阐述表单验证的分类和区别 能够运用表单验证的常用注解 能够编写表单验证的示例 能够编写SSM整合的应用案例 能够总结SSM整合的步骤 1 校验框架 1.1 入门-视 ...

  2. Java对象校验框架之Oval

      只要有接口,就会有参数的校验,目前开源的校验框架已经非常多了,不过不得不提一下Oval.OVal 是一个可扩展的Java对象数据验证框架,验证的规则可以通过配置文件.Annotation.POJO ...

  3. 基于SLF4J的MDC机制和Dubbo的Filter机制,实现分布式系统的日志全链路追踪

    原文链接:基于SLF4J的MDC机制和Dubbo的Filter机制,实现分布式系统的日志全链路追踪 一.日志系统 1.日志框架 在每个系统应用中,我们都会使用日志系统,主要是为了记录必要的信息和方便排 ...

  4. 【转】Dubbo是Alibaba开源的分布式服务框架

    Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常简单的模 ...

  5. Struts2中的校验框架

    Struts2提供的客户端校验 尽管这种支持比较弱,但采用Struts2中的客户端校验时需要注意以下几点 1..将<s:form validate="true">的va ...

  6. 类Shiro权限校验框架的设计和实现(2)--对复杂权限表达式的支持

    前言: 我看了下shiro好像默认不支持复杂表达式的权限校验, 它需要开发者自己去做些功能扩展的工作. 针对这个问题, 同时也会为了弥补上一篇文章提到的支持复杂表示需求, 特地尝试写一下解决方法. 本 ...

  7. Dubbo的Filter链梳理---分组可见和顺序调整

    前言: 刚刚写了篇博文: Dubbo透传traceId/logid的一种思路, 对dubbo的filter机制有了一个直观的理解. 同时对filter也多了一些好奇心, 好奇filter链是如何组织的 ...

  8. Reading | 《TensorFlow:实战Google深度学习框架》

    目录 三.TensorFlow入门 1. TensorFlow计算模型--计算图 I. 计算图的概念 II. 计算图的使用 2.TensorFlow数据类型--张量 I. 张量的概念 II. 张量的使 ...

  9. 【原】Spring和Dubbo基于XML配置整合过程

    背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个 ...

随机推荐

  1. 提取路由器固件中的squashfs

    之前用binwalk -Me提取固件中的squashfs,但会生成大量的压缩包等,只提取文件系统的话,可以定位squashfs的文件头(hsqs)位置,然后用dd将它分离出来,然后在unsquashf ...

  2. ant___令牌过滤器

    令牌过滤器允许我们在复制时过滤文件中的数据.要进行过滤,需要使用一个必须与过滤器任务中的@token @设置匹配的标记.任务使用@作为标记分隔符.为了实现此功能,apache ant提供了使用toke ...

  3. C# 在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke

    http://www.cnblogs.com/fish124423/archive/2012/10/16/2726543.html 在Invoke(....)之前加上1 this.components ...

  4. Docker for windows10 配置阿里云镜像

    到官网下载 并且 安装 Docker for windows  (注意 官方要求 windows10 是企业版才行  天朝你懂的 ) 关于 Docker for windows  要求有  带有 hy ...

  5. 绑定方法与非绑定方法 classmethod和staticmethod

    一:绑定方法:特点:绑定给谁就应该是由谁来调用,谁来调用就会将谁当做第一个参数传入 1:绑定给对象的方法:类中定义的函数默认就是绑定给对象的 例:        2:绑定给类的方法:为类中定义的函数加 ...

  6. Django-2.1基础操作

    创建项目 安装django pip3 install django #查看django版本 django-admin --version python -m django --version 2.1. ...

  7. 基于RobotFramework——自定义kafka库并导入使用

    [Kafka] 首先介绍一下我了解的kafka的皮毛信息—— kafka——一个分布流处理系统:流处理:可以像消息队列一样publish或者subscribe信息:分布式:提供了容错性,并发处理消息的 ...

  8. 如何从零开始在github上新建项目

    准备工作: (1)安装git: Git-2.16.1-64-bit.exe (2)新建一个文件夹grpc007,作为本地git仓库 (3)进入到grpc007目录,右键/打开git bash.使用gi ...

  9. jQuery中$(function(){})与(function($){})(jQuery)、$(document).ready(function(){})等的区别详解

    1.(function($) {…})(jQuery); 1).原理: 这实际上是匿名函数,如下: function(arg){…} 这就定义了一个匿名函数,参数为arg 而调用函数时,是在函数后面写 ...

  10. Vue(一)

    一.es6语法:let和const es6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. 上面代码在代码块之中,分别用let和var声明了两 ...