关于OpenFeign那点事儿 - 使用篇

引言Hello 大家好,这里是Anyin 。
在我们微服务开发过程中不可避免的会涉及到微服务之间的调用,例如:认证Auth服务需要去用户User服务获取用户信息 。在Spring Cloud全家桶的背景下,我们一般都是使用Feign组件进行服务之间的调用 。
关于一般的Feign组件使用相信大家都很熟悉,但是在搭建整个微服务架构的时候Feign组件遇到的问题也都熟悉吗 ? 今天我们来聊一聊 。
基础使用首先,我们先实现一个Feign组件的使用方法 。
1.导入包
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>这里也导入了一个Loadbalancer组件,因为在Feign底层还会使用到负载均衡器进行客户端负载 。
2.配置启用FeignClient
@EnableFeignClients(basePackages = {"org.anyin.gitee.cloud.center.upms.api"})在我们的main入口的类上添加上@EnableFeignClients注解,并指定了包扫描的位置
3.编写FeignClient接口
@FeignClient(name = "anyin-center-upms",contextId = "SysUserFeignApi",configuration = FeignConfig.class,path = "/api/sys-user")public interface SysUserFeignApi { @GetMApping("/info/mobile") ApiResponse<SysUserResp> infoByMobile(@RequestParam("mobile") String mobile);}我们自定义了一个SysUserFeignApi接口,并且添加上了@FeignClient注解 。相关属性说明如下:
•name 应用名,其实就是spring.application.name,用于标识某个应用,并且能从注册中心拿到对应的运行实例信息
•contextId 当你多个接口都使用了一样的name值,则需要通过contextId来进行区分
•configuration 指定了具体的配置类
•path 请求的前缀
1.编写FeignClient接口实现
@RestController@RequestMapping("/api/sys-user")public class SysUserFeignController implements SysUserFeignApi { @Autowired private SysUserRepository sysUserRepository; @Autowired private SysUserConvert sysUserConvert; @Override public ApiResponse<SysUserResp> infoByMobile(@RequestParam("mobile") String mobile) {SysUser user = sysUserRepository.infoByMobile(mobile);SysUserResp resp = sysUserConvert.getSysUserResp(user);return ApiResponse.success(resp); }}这个就是一个简单的Controller类和对应的方法,用于根据手机号查询用户信息 。
2.客户端使用
@Component@Slf4jpublic class MobileInfoHandler{ @Autowired private SysUserFeignApi sysUserFeignApi; @Override public SysUserResp info(String mobile) {SysUserResp sysUser = sysUserFeignApi.infoByMobile(mobile).getData();if(sysUser == null){throw AuthExCodeEnum.USER_NOT_REGISTER.getException();}return sysUser; }}这个是我们在客户端服务使用Feign组件的代码,它就像一个Service方法一样,直接调用就行 。无需处理请求和响应过程中关于参数的转换 。
至此,我们的一个Feign组件基本使用的代码就完成了 。这个时候我们信心满满地赶紧运行下我们代码,测试下接口是否正常 。
以上的代码,是能够正常运行的 。但是随着我们遇到场景的增多,我们会发现,理想很丰满,显示很骨感,以上的代码并不能100%适应我们遇到的场景 。
接下来,我们来看看我们遇到哪些场景以及这些场景需要怎么解决 。
场景一:日志在以上的代码中,因为我们未做任何配置,所以sysUserFeignApi.infoByMobile方法对于我们来讲就像一个黑盒 。
虽然我们传递了mobile值,但是不知道真实请求用户服务的值是什么,是否有其他信息一起传递?虽然方法返回的参数是SysUserResp实体,但是我们不知道用户服务返回的是什么,是否有其他信息一起返回?虽然我们知道Feign组件底层是http实现,那么请求的过程是否有传递header信息?
这一切对我们来讲就是一个黑盒,极大阻碍我们拔刀(排查问题)的速度 。所以,我们需要配置日志,用于显示请求过程中的所有信息传递 。
在刚@FeignClient注解有个参数,configuration 指定了具体的配置类,我们可以在这里指定日志的级别 。如下:
public class FeignConfig {@Beanpublic Logger.Level loggerLevel(){return Logger.Level.FULL;}}接着还需要在配置文件指定具体FeignClient的日志级别为DEBUG 。
logging:level:root: infoorg.anyin.gitee.cloud.center.upms.api.SysUserFeignApi: debug这个时候,你在请求接口的时候,会发现多了好多日志 。


推荐阅读