雅码轩专栏, 干货, 无废话!
OpenFeign的正确用法
传统用法: 单独抽一个模块专门写一堆@FeignClient
, 所有模块都引入此模块, 导致把不需要的客户端也引入了, 冗余大, 而且每个接口都要重复写一遍, 工作量大
正确用法(全新模块化理念): 将模块抽成xxx-api
和xxx-service
两个模块
需要对外暴露的类, DTO, VO写在api模块里, 服务的运行时代码
写在service模块里
案例: 某用户业务模块
- 将用户模块拆分为
xxx-api
和xxx-service
不建议把api和service又合成一个父模块, 实际开发往往追求轻量级, 快速, 简洁, 易理解, 层级越少越清晰, 因为maven的模块化能力, 本身就可以无视文件夹层级
- 区分出3哥概念: 簇点, @Controller, @FeignClient
Feign客户端和Controller都继承或实现簇点接口
IUserHttp
簇点接口
@Tag(name = "用户业务")
public interface IUserHttp {
String PATH_PREFIX = "/user";
@Operation(summary = "获取单个用户",description = "根据userId查询单个用户")
@GetMapping("/{userId}")
R<UserVO> get(@PathVariable("userId") Long userId);
@Operation(summary = "报个错吧", description = "测试报个错,看feign是怎么知道报错了的")
@GetMapping("/throwException")
R<Boolean> throwException();
}
簇点接口定义了这个业务有哪些接口路径
Feign客户端
@FeignClient(value = "user-service", path = IUserHttp.PATH_PREFIX)
public interface UserClient extends IUserHttp {
}
没错, Feign客户端什么都不需要写!!! 直接继承簇点
- 在
user-service
模块中编写controller
因为controller是属于这个微服务的运行时
代码, 他在独立的jvm中运行, 不能暴露给外部.
@Slf4j
@RestController
@RequestMapping(IUserHttp.PATH_PREFIX)
public class UserController implements IUserHttp {
@Override
public R<UserVO> get(Long userId) {
return R.ok(new UserVO().setId(userId));
}
@Override
public R<Boolean> throwException() {
ThreadUtil.sleep(3000);
int a = 1 / 0;
return R.ok(true);
}
}
Controller类也很纯净, 只需要在上方加上@RestController
和@RequestMapping(IUserHttp.PATH_PREFIX)
注解, 为什么要用常量? 因为feign也要指定path前缀 , 两边保持一致
现在, 我要在别的模块引入用户模块
:
<dependency>
<groupId>com.matrix.cloudalibaba</groupId>
<artifactId>user-api</artifactId>
</dependency>
这样便实现了对外和对内的彻底解耦, 想用哪个模块, 就引入哪个模块的api模块,
防止引入冗余的Feign客户端, 也减少了工作量.