各位大佬,最近项目拆分中,使用了 OpenFeign 调用。服务间调用的接口单独写个 api 模块(feign 接口),然后给其他服务进行引用,也就是服务提供方提供。 1.参考其他的有的是在 api 接口把 VO,,DTO,数据库实体都放在这里,但是我们现在这些都在 service 模块中; 2.api 模块 feign 接口的入参和返回,定义为什么呢,service 具体的实现的入参和返回也是引用 api 模块 feign 接口的入参和返回,还是定义自己的,OpenFeign 是可以不一样的,但是具体实现是什么呢; 3.现在 controller 的作用就是调用 service 直接返回,但是现在有人想在 controller 做参数校验+service 调用返回原始数据,不返回 xxxVO ,而是在 controller 包装成 VO 返回,可以根据多种要求返回,编写不同的 VO 对象返回,以前都是直接在 service 校验参数和封装。 4.Feign 接口返回的现在不使用统一对象封装,定义了一个 Decoder,这样就直接返回结果,还是使用统一结果封装 本人学习中,感觉没人的说的或者开源项目中都不一样,不知道具体的比较好的实现是什么
![]() |
1
florentino 2024-04-29 09:06:19 +08:00
本质就是通过 http 调用,至于你说的 VO,DTO 那些东西,可以放在 api 里面让其他服务依赖,也可以不放,调用方自己实现,反正最后都是会被序列化和反序列化的
另外可以不使用 OpenFeign, 实现一个纯 resttemplate 去调用服务,这样你就能理解的更深了 |
2
123zouwen 2024-04-29 09:07:36 +08:00
1. 服务间调用的接口单独写个 api 模块(feign 接口),然后给其他服务进行引用,也就是服务提供方提供
|
![]() |
3
SilenceLL 2024-04-29 09:11:19 +08:00
1. 对内的 Feign 接口单独定义
2. DTO VO 这些抽离,按需引用 3. feign client 单独抽离,按需引用 |
4
123zouwen 2024-04-29 09:14:08 +08:00
1. 服务间调用的接口单独写个 api 模块(feign 接口),然后给其他服务进行引用,也就是服务提供方提供
不是一定要求这个. 如果多个服务是不同语言的, 这样做没什么意义. 你就把它当成一个普通的对外提供服务的接口就行了,做好幂等处理. 2. 既然是都是对外提供的接口了, 入参和出参 你提供接口文档就行了, 别的服务想定义什么实体都行. 3. 服务拆分的时候,要明确拆分是否有必要? 我见过很多为了拆分而拆分的, 明明可以是在一起的,拆完后又要上分布式事务中间件,意义何在? 我觉得这是把单体思维代入到了微服务中. 分布式事务中间件个人觉得没有任何必要, 但很多 java 总希望能跟写单体服务一样直接 rpc 调用还能处理好事务. 都做服务拆分了,这些服务完全都可以用不同语言写,做好幂等. openFeign 也就是服务间的 http 调用 |
![]() |
5
RedBeanIce 2024-04-29 10:03:33 +08:00
我们在项目中抛弃了 feign 。。
但是写 go 的时候,又用了 grpc+protobuf ,,,不知道是好还是坏。 |
6
sighforever 2024-04-29 11:25:07 +08:00
既然 api 已经会共享出去被其他项目引用,那比较好的设计就是这一层是独立的。
所有在接入层的数据实体也定义在提供的包里面。 对内只有 controller 层使用 api 层里面的数据,service 层不使用 api 层的数据实体,而是自己再定义一套,由 controller 层负责转换。 对于第三方,也可以直接调用 api 暴露出来的实体和你的服务交互了。 |
![]() |
7
tom 2024-04-29 11:49:01 +08:00 ![]() 1 楼 @florentino 说的“本质就是通过 http 调用,至于你说的 VO,DTO 那些东西,可以放在 api 里面让其他服务依赖,也可以不放,调用方自己实现,反正最后都是会被序列化和反序列化的”
以及 4 楼 @123zouwen 说的“我觉得这是把单体思维代入到了微服务中. 分布式事务中间件个人觉得没有任何必要, 但很多 java 总希望能跟写单体服务一样直接 rpc 调用还能处理好事务.” 都非常对,是非常正确的微服务理念。基本上你从网上看到的绝大部分理论,都是指导你灵活使用,因为脱离了实际使用场景,并不会存在一个最佳实践。 而你困惑的地方在于,你没描述出来你们完整的工程场景,上面他们所说的都不足以解答你的疑惑,feign 用起来总是感觉有点不伦不类,对不对 我猜你是做 toB 的行业软件,业务逻辑复杂,功能点多,架构师又采用微服务形式,然后甚至一个功能模块一个微服务,从功能划分上倒是合理,但是呢,各模块之间的交付是很频繁及复杂的,互相调用的情况非常多, 硬套上微服务, 很难复用代码 & 控制事务, 如果各自解析 feign 的返回,还容易造成混乱(各种业务逻辑频繁变动、数据模型满天飞, 有些对象能有 200 多个属性)。 我是非常不建议也不喜欢大部分 toB 业务使用微服务开发的,不合适。 当然你们已经这么做了,我的建议是,各自模块的 DTO 、VO 、等 POJO ,自行维护。需要被其他模块调用的,复制一份 POJO 到 api 模块中,写好文档,做好代码同步即可。这样调用方不用关心如何解析,调用结果会自动转换为 POJO 对象,省心省事,又贴合单体应用的使用习惯。 有条件的话,还是从微服务的巨坑里爬出来吧。 |
8
chawuchiren 2024-04-29 12:03:12 +08:00
@RedBeanIce 我感觉只要 grpc 不是用的 json ,都很好
|
9
MarioLuo 2024-04-29 13:17:38 +08:00
服务拆分后各个服务之间通过 http 接口调用,那么第一个问题考虑的是要不要提供客户端?
第一种: 服务分为多个 maven 模块, 例如: user-api, user-provider, 优点代码复用, 缺点就是版本兼容,适合大量接口调用. 第二种: 调用方写代码调用,优点是按需写、灵活,缺点就是代码重复,适合少量接口调用. 第三种: 单独写一个 sdk 项目,优点是复用,缺点单独维护,也可根据 openapi 文档自动生成. 回到你的问题,如果使用第一种方式: 1. API 包种每个接口返回 VO/DTO, 不要直接返回数据库实体类,实体放在实现模块中,实体转换用 mapstract 即可。 2. Feign 中每个接口建议入参和返回都包装一个实体: UserAddReq, UserAddResp 以后便于扩展而不影响调用方,部分原子接口可不用包装比如根据 id 获取用户信息: Result<UserDTO> getUserById(@PathVariable("id") Long id); 3.因为我们是 bff 模式,原子服务的 service 层尽量返回实体,控制层包装转化为 DTO/VO; 4.目前我们是返回的 Result<?>, 然后 Result 里有个 tryThrow()方法,由调用方控制,灵活性更大,也可以用 Decoder 方式; 另外一个小地方命名冲突: 一般会在 bff 服务中请求响应都叫 XXxReqVO, XxxRespVO, 而在原子服务叫: XxxReq, XxxResp 。 我们实际中采用第一种和第二种混合: bff 服务调底层服务用第一种,相对独立或外部的服务调用使用第二种。 |
![]() |
10
listkun 2024-04-29 13:38:42 +08:00
feign 的本意是让你调用别人的时候,可以定义发送和接收的对象类,
分发出去的接口是 http 的,给出 http 文档即可,至于调用方用什么语言不重要 |
![]() |
11
nitouge OP 多谢各位大佬的回复,受益匪浅. 项目的确是 tob,之前是微服务,模块比较少,一个主要的微服务,其他一些辅助的服务,现在是要做产品化,把那一个主要的服务拆分出单独的服务,这样可以单独收费,其他的可以按需要引入服务。目前给的时间多,我想考虑好再做
|
![]() |
12
smartychaos 2024-04-29 17:00:20 +08:00
有几种选择, 第一种是在 api 包( client api )里定义所需实体 VO, 服务端 web 包引用并实现这些 api 接口,实体可以直接引用。当然服务使用者也可以用,大家都便利。
|
13
flmn 361 天前
所以,干嘛不用 grpc 呢
|