客户端远程调用 Feign 什么是Feign?
Feign是 Netflix 公司开源的声明式HTTP客户端
Github : Feign 源码
为什么需要Feign?原代码可读性不高
复杂的URL难以维护(https://user-center/s?wd={userId}&rsv_spt=1&rsv_iqid=0x93bff3cd000cf3da&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=4&rsv_sug1=4&rsv_sug7=100&rsv_t=10c2risCimsUZC0RBruMerdnQRN1gRxFI%2BywuD0L3LwGGNd2dR8XE6x%2FyFOjHnR0oEi0&rsv_sug2=0&inputT=1535&rsv_sug4=1535&rsv_sug=2)
难以应对需求的快速变化
编码体验和我们写JAVA差异较大
举例重构代码 //替换前 ResponseEntity<UserDTO> userEntity = restTemplate.getForEntity( "http://user-center/users/{userId}", UserDTO.class, userId ); UserDTO userDTO = new UserDTO(); if (null != userEntity) { userDTO = userEntity.getBody(); log.info("ShareService#findById userDTO: {}", userDTO); }添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>启动类添加注解 @EnableFeignClients
添加配置
实现对应微服务的client
/** * IUserCenterFeignClient for 定义 user-center feign client * * @author <a href="http://www.likecs.com/mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> * @since 2019/7/15 */ @FeignClient(name = "user-center") public interface IUserCenterFeignClient { /** * Feign client 会将请求转换为 * {userId} * * @param userId 用户id * @return 返回用户对象 */ @GetMapping(path = "/users/{userId}") public UserDTO findById(@PathVariable Long userId); }替换后代码
//使用 FeignClient 来替换掉RestTemplate调用 UserDTO userDTO = this.userCenterFeignClient.findById(userId); Feign的组成 Feign的配置方式 Java Code 支持的配置项 自定义Feign日志级别级别内容
DemoTip : 有可能出现父子上下文重叠问题
在client添加配置
/** * IUserCenterFeignClient for 定义 user-center feign client * * @author <a href="http://www.likecs.com/mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> * @since 2019/7/15 */ @FeignClient(name = "user-center",configuration = UserCenterFeignConfiguration.class) public interface IUserCenterFeignClient { ... }编写java配置文件
/** * UserCenterFeignConfiguration for 自定义user-center服务请求中,feign的配置信息 * {@link @Configuration} 不能添加该注解,否则会和ribbon一样,出现上下文重叠问题,造成配置全局共享 * 如要添加该注解,需要将该类放在主程序启动扫描不到的包下 * * @author <a href="http://www.likecs.com/mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> * @since 2019/7/15 */ public class UserCenterFeignConfiguration { @Bean public Logger.Level level() { // 配置feign 日志级别,记录请求和响应的header、body以及元数据 return Logger.Level.FULL; } }
一定要在配置文件中添加该client 全路径
logging: level: #com.sxzhongf: debug com.sxzhongf.sharedcenter.feignclients.IUserCenterFeignClient: debug打印信息
2019-07-15 15:06:11.650 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] <--- HTTP/1.1 200 (402ms) 2019-07-15 15:06:11.651 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] content-type: application/json;charset=UTF-8 2019-07-15 15:06:11.651 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] date: Mon, 15 Jul 2019 07:06:11 GMT 2019-07-15 15:06:11.651 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] transfer-encoding: chunked 2019-07-15 15:06:11.652 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] 2019-07-15 15:06:11.652 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] {"id":1,"wxId":"","wxNickname":"IsaacZhang","roles":"","avatarUrl":"aaa","createTime":"2019-07-11T06:08:18.000+0000","updateTime":"2019-07-11T06:08:18.000+0000","bonus":100} 2019-07-15 15:06:11.652 DEBUG 20286 --- [nio-8010-exec-1] c.s.s.f.IUserCenterFeignClient : [IUserCenterFeignClient#findById] <--- END HTTP (173-byte body) Configuration 支持的配置项 demo使用配置文件来定义log level
#logging: #level: #com.sxzhongf: debug #com.sxzhongf.sharedcenter.feignclients.IUserCenterFeignClient: debug feign: client: config: user-center: #单服务配置 loggerLevel: full --- feign: client: config: default: #全局配置日志级别 loggerLevel: full Feign的继承性官方不建议使用
大多数公司使用?
架构师需要根据自身业务情况来决定,是否需要将不同的微服务进行业务耦合,还是使用冗余代码的方式来解放业务耦合性。
Feign多参请求 Get使用@SpringQueryMap
@FeignClient(name = "user-center") public interface ITestUserCenterFeignClient { @GetMapping("/users/q") public UserDTO query(@SpringQueryMap UserDTO userDTO); }