OpenFeign 是一个基于 Netflix Feign 实现的 Java HTTP 客户端开发工具,它简化了使用 Ribbon 时自定义 http 请求的过程。OpenFeign 通过注解的方式定义和实现了 RESTful API 的接口,使得调用远程 HTTP 服务更加简单和易用。本文将从多个方面对 OpenFeign 进行详细阐述。
一、OpenFeign原理
OpenFeign 在实现上是基于 Feign 的,其底层依赖 Ribbon。Ribbon 是一个负载均衡客户端,它可以自动化地完成客户端的负载均衡。OpenFeign 通过注解的方式定义和实现了 RESTful API 接口,并集成了 Ribbon,将 RESTful API 接口转化为 HTTP 请求并发送,最后将返回的数据转化为接口的返回值。 OpenFeign 的主要原理如下: 1. 用户通过接口定义和注解的方式定义一个 RESTful 接口 2. OpenFeign 在运行时会自动生成一个接口的代理类 3. 每当用户通过代理类调用接口时,OpenFeign 实际上会通过 Ribbon 向多个服务实例发送 HTTP 请求 4. Ribbon 会根据负载均衡算法选出一台可用的服务,并将请求发送给该服务 5. 接收到请求的服务会将请求转化成数据 6. 返回的数据再会被 OpenFeign 自动转换成接口期望的返回值类型,并返回给调用方
二、OpenFeign使用什么网络协议
OpenFeign 的底层网络协议是 HTTP 协议。 在帮助开发者快速开发微服务架构中,它可以与 Eureka、Zookeeper 等注册中心进行集成使用,并支持多种 HTTP 注解及默认集成了 Ribbon 。
三、OpenFeign使用
下面分别对 OpenFeign 的注解和配置进行介绍。
1. 注解
@FeignClient 注解 该注解用于声明一个 Feign 客户端,并定义服务名称和路径前缀。其中: - value属性为远程服务名,即 Eureka 注册中心中的服务名,如果不指定,则使用 HTTP 地址; - path属性为微服务的 context-path,可理解为修改调用的 URL 前缀,会被自动添加到所有请求地址前面。 例如: ```java @FeignClient(value = "hello-service", path = "/api") public interface Client { @GetMapping("/hello") String hello(); } ``` @RequestMaping 注解 该注解用于声明一个 HTTP 请求,包括 `GET` 、 `POST` 、 `PUT` 、 `DELETE` 、 `HEAD` 、 `OPTIONS` 、 `PATCH` 等请求方式,并且可以指定请求路径的 URL、请求参数、请求体等信息。 例如: ```java @FeignClient(value = "hello-service", path = "/api") public interface Client { @RequestMapping(value = "/hello", method = RequestMethod.GET) String hello(); @RequestMapping(value = "/greeting", method = RequestMethod.POST) String greeting(@RequestBody User user); } ```
2. 配置
OpenFeign 也支持一些相关的配置,如请求超时时间、日志级别等。 以下是服务提供方主体类中的 OpenFeign 配置: ```java @EnableFeignClients @RibbonClient(name = "hello-service") @SpringBootApplication public class App { @Bean public RequestInterceptor requestInterceptor(){ return new FeignRequestInterceptor(); } public static void main(String[] args) { SpringApplication.run(App.class, args); } } ``` 其中,使用 `@RibbonClient` 声明 Ribbon 客户端,name指定微服务名称;使用 `@EnableFeignClients` 启用 Feign 客户端;通过定义一个 RequestInterceptor 来实现请求响应拦截。
四、OpenFeign源码
OpenFeign 的源码托管在 GitHub 上,仓库的地址为:https://github.com/OpenFeign/feign。
五、OpenFeign面试题
1. OpenFeign 的原理是什么? 2. OpenFeign 使用什么网络协议? 3. OpenFeign 如何定义 HTTP 请求? 4. 如何使用 Ribbon 和 Feign 集成负载均衡? 5. 如何设置 OpenFeign 的请求超时时间和日志级别?
六、OpenFeign和Feign的区别
Feign 是一个 RESTful 的 HTTP 客户端工具,是 Netflix 开源的,主要用于快速开发 RESTful 声明式 Web 服务。而 OpenFeign 是对 Feign 进行了扩展和增强,主要在以下方面有所优化: 1. 在 Feign 的基础上增加了 Ribbon 的支持 2. 增加了对 Hystrix 的支持,可实现服务的负载均衡和断路器模式 3. 加强了对 Spring Boot 的支持
七、OpenFeign和Feign
在很多方面,OpenFeign 应该与 Feign 等效,在使用上差不多。 OpenFeign 实现了 Feign 的功能,再加上了对 Eureka、Ribbon 和 Hystrix 的支持,使得它更加适用于微服务架构。
八、调用直接报数据转换失败
在使用 OpenFeign 进行微服务互调时,可能会遇到以下错误: ``` com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token ``` 这是因为默认情况下,OpenFeign 会使用 Jackson 将 JSON 数据转换为接口的返回值类型,但是接口的返回值类型不匹配 JSON 数据的格式。 为了解决这个问题,需要自定义一个对象承接返回的数据,如下: ```java public class Result
{ private Integer code; private String message; private T data; //... getter and setter } ``` 然后,在接口的返回值类型中使用该对象代替,并在 Feign 的配置中增加对返回数据的转化,如下: ```java @EnableFeignClients(basePackages = "com.example.feignclient") @SpringBootApplication public class Application { @Bean public Decoder decoder() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return new ResponseEntityDecoder(new SpringDecoder(new ObjectMapper())); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ```
九、OpenFeign底层原理
OpenFeign 的底层原理可以概括如下: 1. 使用 Java 动态代理机制,将接口的方法生成一个代理类 2. 通过 Spring Cloud Discovery Client 实现的 Ribbon 进行服务发现并进行负载均衡 3. 将请求拼接成 HTTP 请求发送出去,未针对请求结果进行处理 4. 得到结果后通过 Spring Cloud 的消息转换器进行解码并将数据传递给 Consumer 端。 通过这个实现,OpenFeign 将服务间的调用、异常处理、超时等都做得很好,方便了开发者进行服务调用和服务治理。