Contents

起因是因为,最近在做公司的项目,我做的是前端系统,取数据需要调用后端系统,我能做的事情不多,所以对于返回值校验这块起来兴趣,而且我们调用后端接口,是内部的一个服务平台。我们前端的微服务,有一个微服务作为统一的调用内部服务平台的入口,所以先通过feign调用到这个组件,再通过这个组件去调用内部服务平台。这样做的好处是,只需要配置一个地方的服务平台参数,就能所有服务公用。但用的不舒服的地方就是返回值是一个map,没有类型信息,不清楚里面有什么值,好处是通用。所以我还是想用bean去接收返回值,然后去校验字段,处理这些异常。

提取出问题的几个关键点,内部服务平台因为所以服务都需要用,但每个微服务都配置麻烦,所以就集中一个微服务配置,其他服务通过feign调用,该组件集中调用内部服务平台,然后透传给每个微服务。我们将该调用内部服务平台的微服务定义为A服务,A服务与其他微服务为了通用,就使用map作为返回值,因为不想每次都开发新接口给每个微服务,因为A服务没有每个接口类型信息,所以也就不能给每个调用者转类型,这也是一种处理方式。然后每个微服务自己从map里取值,通过map在业务里传递,完成处理。这也是一种行得通的设计。

但这种设计的缺陷就是,后面的人不好维护,非开发的人找不到接口里到底有什么值,map没有任何类型信息,字段意义,开发方面,但维护成本高。所以我倾向于使用bean去作为接收对象,在业务中传递,既可以校验,也有字段信息,缺点就是可能bean会很多,膨胀的很厉害。这是以编译期类型信息代替运行时类型信息。这就是第一个分歧点,使用编译器校验还是运行期,表面上的争议是bean还是map。

我要实现的功能是返回值字段校验与统一校验异常处理,
思路1,如果返回值是map,那就一个个字段取出,校验,然后处理异常。缺点:人工做,容易错误,繁琐。好处:效率高。
思路2,返回值还是map,map转bean,然后bean做校验处理。后面的bean的校验统一用hibernate validator处理。缺点:map转bean,多种方法实现,反射等方法有性能较低,高性能转换需要引入其他框架。
思路3,返回是bean,在使用其他方面,单独校验处理异常。
这里有一个重要的点,就是调用使用的feign调用,业务B服务,调用A服务,A服务会进行json转换,再调用内部服务平台,返回值,再json序列号,发给B服务,B服务的feign再反序列化。
思路3.1,A服务要有B服务的返回值类型,然后在内部平台返回时,先反序列化成B服务的类型,再返回给B,这样A服务,要有所有服务的类型信息,不太合适,A服务应该不频繁改动。
思路3.2,A服务,既然不能有类型信息,那就不解析,直接透传呢?好像问题解决了。因为内部平台正好也是json类型的返回值,直接在A服务,不解析json,直接返回给B,B用类型信息去解析,这是透传还不能消耗json解析的时间。这个地方,返回值使用string,然后produces使用json,spring mvc可以直接返回json。返回bean的第一个问题,解决了,可以不用map,直接在B服务用Bean去接收。

然后是校验的部分,
思路1,独立的部分去校验bean,返回值校验失败返回值,但不抛异常,单独一个方法再包装抛异常
思路2,在feign的decode的时候,去解析bean,校验字段,抛异常
这两个思路应该都支持,第一种更通用,第二种更简单。

在feign的前后做好校验与异常,相当于定了接口,对于不同系统的管理也更方便。

总结:通过不解析json进行透传,省略中间服务类型转换。通过feign前后encode与decode的重写,来处理bean的校验和异常的处理,bean的校验框架使用hibernate validator进行。

Contents