OpenFeign 远程调用基本原理和使用
OpenFeign 远程调用基本原理和使用
之前已经把 Eureka、Ribbon 集成到我的小商城系统了,今天把 OpenFeign 远程调用组件集成了。
比较有趣的一点是 Feign 和 OpenFeign 这两个小家伙,这里做个总结:
Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由社区进行维护,更名为 OpenFeign。
Feign是 Springcloud组件中的一个轻量级 Restful的 HTTP 服务客户端,Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
OpenFeign 是 Springcloud 在 Feign的基础上支持了 SpringMVC 的注解,如 @RequestMapping 等等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
源码地址:https://github.com/openfeign/feign
代码示例
OpenFeign 的使用也很简单,这里还是用我的开源 SpringCloud 项目 PassJava 作为示例。
开源地址: https://github.com/Jackson0714/PassJava-Platform
喜欢的小伙伴来点个 Star 吧,冲 2K Star。
Member 服务远程调用 Study 服务的方法 memberStudyTime(),如下图所示。
第一步:Member 服务需要定义一个 OpenFeign 接口:
@FeignClient("passjava-study")
public interface StudyTimeFeignService {
@RequestMapping("study/studytime/member/list/test/{id}")
public R getMemberStudyTimeListTest(@PathVariable("id") Long id);
}
我们可以看到这个 interface 上添加了注解@FeignClient
,而且括号里面指定了服务名:passjava-study。显示声明这个接口用来远程调用 passjava-study
服务。
第二步:Member 启动类上添加 @EnableFeignClients
注解开启远程调用服务,且需要开启服务发现。如下所示:
@EnableFeignClients(basePackages = "com.jackson0714.passjava.member.feign")
@EnableDiscoveryClient
第三步:Study 服务定义一个方法,其方法路径和 Member 服务中的接口 URL 地址一致即可。
URL 地址:"study/studytime/member/list/test/{id}"
@RestController
@RequestMapping("study/studytime")
public class StudyTimeController {
@RequestMapping("/member/list/test/{id}")
public R memberStudyTimeTest(@PathVariable("id") Long id) {
...
}
}
第四步:Member 服务的 POM 文件中引入 OpenFeign 组件。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第五步:引入 studyTimeFeignService,Member 服务远程调用 Study 服务即可。
Autowired
private StudyTimeFeignService studyTimeFeignService;
studyTimeFeignService.getMemberStudyTimeListTest(id);
通过上面的示例,我们知道,加了 @FeignClient 注解的接口后,我们就可以调用它定义的接口,然后就可以调用到远程服务了。
这里你是否有疑问:为什么接口都没有实现,就可以调用了?
OpenFeign 使用起来倒是简单,但是里面的原理可没有那么简单,OpenFeign 帮我们做了很多事情,接下来我们来看下 OpenFeign 的架构原理。
QA
1、遇到报错:Unregistering application *** with eureka with status DOWN
在出错项目的pom依赖中添加如下依赖:
https://blog.csdn.net/weixin_45763431/article/details/114013665
2、404 not found
FeignClient 对应的 API 方法,上面的 URL 路径需要和 controller 定义的 API 路径一致。
3、405
Service A
2022-07-04 11:11:50.979 ERROR 33552 --- [nio-9642-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$MethodNotAllowed: [405] during [GET] to [http://lic-example-service/member/v1/list] [FeignMemberService#getUserinfoList(Member)]: [{"timestamp":"2022-07-04T03:11:50.315+00:00","status":405,"error":"Method Not Allowed","message":"","path":"/member/v1/list"}]] with root cause
Service B
2022-07-04 11:11:50 [http-nio-9640-exec-3] WARN org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver -Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
解决方案:
Get 请求传对象,需要加 @SpringQueryMap
@GetMapping("/member/v1/list")
R<List<Member>> getUserinfoList(@SpringQueryMap Member member);