OpenFeign服务接口调用
OpenFeign服务接口调用
OpenFeign概述
1. LoadBalancer和OpenFeign的区别
LoadBalancer 和 OpenFeign 都是用于微服务架构中的不同工具,但它们的作用和使用场景不同。
-
LoadBalancer:主要用于在多个服务实例之间分配请求,以实现负载均衡。它负责将请求分发到不同的服务实例,从而提高服务的可用性和性能。
-
OpenFeign:是一个声明式的 HTTP 客户端,主要用于服务之间的通信。OpenFeign 允许你通过简单的注解方式定义服务接口,而不需要自己编写复杂的 HTTP 客户端代码。OpenFeign 可以与 LoadBalancer(客户端负载均衡器)结合使用,提供客户端侧的负载均衡功能。
为什么需要学习 OpenFeign?
即使你已经有了 LoadBalancer,用 OpenFeign 仍然有以下几个好处:
- 简化服务调用:你不需要手动处理 HTTP 请求和响应,OpenFeign 会帮你自动处理这些细节。
- 增强可读性和维护性:通过声明式的接口,代码更加直观,容易理解和维护。
- 灵活性和扩展性:OpenFeign 可以轻松集成其他功能,比如日志记录、请求拦截等。
2. LoadBalancer和OpenFeign应该使用哪一个
如果你的微服务架构中需要频繁进行服务间通信,且希望代码更简洁和可维护,那么建议你日常使用 OpenFeign。LoadBalancer 可以与 OpenFeign 结合使用,帮助你实现客户端的负载均衡。
但如果你只关注于服务实例之间的负载均衡,而不涉及服务之间的复杂调用,LoadBalancer 可能已经足够。实际上,在大多数场景下,OpenFeign 和 LoadBalancer 是互补的,经常会一起使用。
3. 什么是 OpenFeign?
OpenFeign 是一个声明式的 HTTP 客户端,主要用于简化微服务之间的调用。它允许你通过注解的方式定义服务接口,而不需要手动编写 HTTP 请求代码。
4. OpenFeign 能干什么?
OpenFeign 是一个功能强大的工具,能够在微服务架构中简化和增强服务间的通信。它的主要功能包括:
-
可插拔的注解支持:OpenFeign 支持使用注解来定义服务接口,包括 Feign 注解和 JAX-RS 注解。这种方式使得定义 HTTP 请求变得更加直观和简洁,同时也支持通过插件扩展注解的功能。
-
支持可插拔的 HTTP 编码器和解码器:OpenFeign 允许你自定义和扩展 HTTP 请求和响应的编码器和解码器。这意味着你可以根据需要使用不同的数据格式(如 JSON、XML)或自定义的格式来传递数据。
-
支持 Sentinel 和它的 Fallback:OpenFeign 可以与 Alibaba 的 Sentinel 集成,用于实现服务的熔断、限流和降级功能。当某个服务出现问题时,Sentinel 能够自动调用定义好的 Fallback 方法,从而保证系统的稳定性。
-
支持 Spring Cloud LoadBalancer 的负载均衡:OpenFeign 可以与 Spring Cloud LoadBalancer 结合使用,实现客户端的负载均衡。通过这种方式,OpenFeign 可以在多个服务实例之间自动分配请求,从而提高系统的可用性和响应速度。
-
支持 HTTP 请求和响应的压缩:OpenFeign 还支持对 HTTP 请求和响应进行压缩处理,减少网络传输的数据量,提高传输效率。这对于大型数据传输场景特别有用。
OpenFeign基本用法
在启动类中加入@EnableFeignClients注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul为注册中心时注册服务
@EnableFeignClients(basePackages = "com.cluod.stores.api")//该注解用于构建OpenFeign
//(basePackages = "com.cluod.stores.api")是指定OpenFeign服务端包在哪里
public class SpringApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApplication.class, args);
}
}
编写服务者代码ProviderController
import com.cluod.commons.resp.ResultData;//编写的返回封装类
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Tag(name = "服务端", description = "模仿服务提供者")
public class ProviderController {
@GetMapping("provider/store/get/{num}")
public ResultData<String> getStore(@PathVariable("num") Integer num) {
return ResultData.success("provider store get " + num);
}
}
编写StoreClient服务接口
- 注意接口中的api应该与ProviderController中的方法参数完全一样
import com.cluod.commons.resp.ResultData; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; // 服务提供者的在consul(服务注册中心)中的名称 @FeignClient(value = "cloud-payment-service") public interface StoreClient { @GetMapping("provider/store/get/{num}") public ResultData getStore(@PathVariable("num") Integer num); }
编写ConsumerController消费者
import com.cluod.stores.api.StoreClient;
import com.cluod.commons.resp.ResultData;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Tag(name = "消费端", description = "模仿消费者")
public class ConsumerController {
@Resource
private StoreClient storeClient;
@GetMapping("consumer/store/get/{num}")
private ResultData<String> getStore(@PathVariable("num") Integer num) {
return storeClient.getStore(num);
}
}
服务调用流程
- 用户在调用ConsumerController的getStore()方法的时候,OpenFeign服务调用接口storeClient会根据@FeignClient()内的服务名称或者ip去调用对应服务上的API,以实现微服务实例之间的调用。
OpenFeign详解
1.覆盖OpenFeign默认值
每个 feign 客户端都是组件集合(这个集合是所以提供相同服务的客户端)的一部分,这些组件协同工作以按需联系远程服务器(由feign客户端主动的去联系服务器,这个服务器可以是Consul),并且该集合具有一个名称,您可以作为应用程序开发人员使用注释为其提供该名称。
Spring Cloud 允许您通过使用声明其他配置(在 之上)来完全控制假客户端。
例如注解:@FeignClient
,通过传入指定参数,对服务名称进行定义以控制
@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
//..
}
在这种情况下,客户端由已存在FooConfiguration以及 FeignClientsConfiguration 中的任何组件组成(其中前者将覆盖后者)
🛈 Note:
FeignClientsConfiguration
是Spring Cloud
提供的一个默认配置类,主要用于配置 Feign 客户端。它包含了 Feign 客户端的基本设置,如编码器、解码器、契约、日志记录等。
在 Spring Cloud 中,当你使用@EnableFeignClients
或@FeignClient
注解时,FeignClientsConfiguration
会自动加载并应用到你的 Feign 客户端。这使得 Feign 客户端能够以 Spring 的方式进行配置和管理。
🛈 Note:
FooConfiguration
不需要使用@Configuration
进行注解。然而,如果确实进行了注解,那么需要注意将其排除在任何会包含此配置的@ComponentScan
之外,否则它将成为默认的feign.Decoder
、feign.Encoder
、feign.Contract
等配置源。可以通过将它放在与任何@ComponentScan
或@SpringBootApplication
不重叠的包中来避免这种情况,或者可以在@ComponentScan
中显式地将其排除。
🛈 Note:
使用@FeignClient
注解中的contextId
属性,除了更改客户端集合的名称外,它还会覆盖客户端名称的别名,并且将被用作为该客户端创建的配置 bean 的名称的一部分。
⚠️ Warning:
以前,使用 url 属性时,不需要指定 name 属性。现在使用时,name 属性是必需的。
支持使用占位符在 name 和 url 属性。
@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
//..
}
🛈 Note:
spring-cloud-starter-openfeign
支持spring-cloud-starter-loadbalancer
。但是,由于它是一个可选依赖项,如果你想使用它,需要确保已将其添加到你的项目中。
要使用基于 OkHttpClient 的 Feign 客户端,请确保 OKHttpClient 位于类路径中,并设置 spring.cloud.openfeign.okhttp.enabled=true
。
对于基于 Apache HttpClient 5 的 Feign 客户端,只需确保 HttpClient 5 在类路径中即可,但你仍然可以通过设置 spring.cloud.openfeign.httpclient.hc5.enabled=false
来禁用其在 Feign 客户端中的使用。在使用 Apache HC5 时,你可以通过提供一个 org.apache.hc.client5.http.impl.classic.CloseableHttpClient
类型的 bean 来自定义使用的 HTTP 客户端。
你还可以通过在属性中设置值进一步自定义 HTTP 客户端。仅以 spring.cloud.openfeign.httpclient.xxx
为前缀的那些将适用于所有客户端,以 httpclient
为前缀的那些适用于 Apache HttpClient 5,以 httpclient.okhttp
为前缀的那些适用于 OkHttpClient。你可以在附录中找到可以自定义的属性的完整列表。
💡 Tip:
从Spring Cloud OpenFeign 4
开始,不再支持Feign Apache HttpClient 4
。我们建议改用Apache HttpClient 5
。
Spring Cloud OpenFeign 默认不为 Feign 提供以下 Bean,但仍然会从应用程序上下文中查找所需要的 Bean 来创建 Feign 客户端。
发展阶段 | 时间 | 逻辑元件 | 速度(次/秒) | 内存 | 外存 |
---|---|---|---|---|---|
第一代 | 1946-1957 | 电子管 | 几千 - 几万 | 延迟线, 磁鼓 | 穿孔卡片, 纸带 |
第二代 | 1958-1964 | 晶体管 | 几万 - 几十万 | 磁芯存储器 | 磁带 |
第三代 | 1964-1971 | 中小规模集成电路 | 几十万 - 几百万 | 半导体存储器 | 磁带, 磁盘 |
第四代 | 1972-现在 | 大规模, 超大规模集成电路 | 上千万 - 万亿 | 半导体存储器 | 磁盘, 磁带, 光盘, 半导体存储器 |