OpenFeign
文章目录
一、简单使用
1.导入依赖
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.配置开启
主启动类添加@EnableFeignClients
注解
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class CloudalibabaConsumerNacosOrder83Application {
public static void main(String[] args) {
SpringApplication.run(CloudalibabaConsumerNacosOrder83Application.class, args);
System.out.println("启动成功");
}
}
3.写OpenFeign接口
import com.wzy.springcloud.alibaba.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
//value值为要调用的目标微服务名
@FeignClient(value="nacos-payment-provider")
public interface FeignTool {
/**
* get请求参数传递,路径参数
* */
@GetMapping(value = "/payment/nacos/path/{id}/{name}")
String getPath(@PathVariable("id") Integer id,@PathVariable("name")String name);
}
4.写controller调用
FeignTool为上面的OpenFeign接口
@RestController
@Slf4j
@RequestMapping("consumer")
public class OrderNacosController {
@Autowired
private FeignTool feighTool;
//get请求参数传递,rest路径参数
@GetMapping(value = "/payment/nacos/path/{id}/{name}")
String getPath(@PathVariable("id") Integer id,@PathVariable("name")String name){
return feighTool.getPath(id,name);
}
}
5.被调用服务
写被调用服务接收的controller
@RestController
public class PaymentController {
@GetMapping(value = "/payment/nacos/path/{id}/{name}")
public String getPath(@PathVariable("id") Integer id,@PathVariable("name")String name) {
return "id:" + id+","+"name:"+name;
}
}
6.日志级别
openfeign有4种日志级别,从低到高:
NONE
:默认级别,不显示日志
BASIC
:仅记录请求方法、URL、响应状态及执行时间
HEADERS
:除了BASIC中定义的信息之外,还有请求和响应头信息
FULL
:除了HEADERS中定义的信息之外,还有请求和响应正文及元数据信息
配置类:
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* openFeign有四种日志级别
* NONE
* BASIC
* HEADERS
* FULL
*
* */
@Configuration
public class openFeignLogger {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
yml配置:
#日志记录器(Logger)的行为是分等级的:
#分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。
#Log4j建议只使用四个级别,优先级 从高到低分别是 ERROR、WARN、INFO、DEBUG。
logging:
level:
#openFeign日志以什么级别监控哪个接口
com.wzy.springcloud.alibaba.service.FeignTool: debug
BASIC配置及日志打印效果:
HEADERS配置及日志打印效果:
FULL配置及日志打印效果:
日志名词解析
Keep-alive:
Keep-alive使客户端到服务器端的连接持续有效,当出现对服务器的后续请求时,Keep-alive功能避免了建立或者重新建立连接。现在的大多数Web服务器都支持Keep-alive。
Keep-alive:timeout=5,max=100
意思是说:过期时间5秒,max是最多100次请求,强制断掉连接,也就是在timeout时间内每来一个新的请求,max会自动减1,直到为0,强制断掉连接。
Transfer-Encoding:chunked:
分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种数据传输机制,允许HTTP由网页服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供。
通常,HTTP应答消息中发送的数据是整个发送的,Content-Length消息头字段表示数据的长度。数据的长度很重要,因为客户端需要知道哪里是应答消息的结束,以及后续应答消息的开始。然而,使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。通常数据块的大小是一致的,但也不总是这种情况。
7.服务降级
yaml配置文件:
feign:
hystrix:
enabled: true
接口代码,fallback为降级调用类,即接口调用报错使用此类返回
import com.service.impl.PaymentFallbackServiceImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
//fallback为降级调用类,即接口调用报错使用该类返回信息
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackServiceImpl.class)
public interface PaymentHystrixService {
@GetMapping("/pay/hy/ok/{id}")
String paymentInfoOK(@PathVariable("id") Integer id);
@GetMapping("/pay/hy/to/{id}")
String paymentInfoTimeOut(@PathVariable("id") Integer id);
}
降级类:
import com.service.PaymentHystrixService;
import org.springframework.stereotype.Component;
public class PaymentFallbackServiceImpl implements PaymentHystrixService {
@Override
public String paymentInfoOK(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
}
@Override
public String paymentInfoTimeOut(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
}
}
8.openfeign通讯优化,GZIP压缩
GZIP简介
gzip介绍:
gzip是一种数据格式,采用用deflate算法压缩数据;gzip是一种流行的数据压缩算法,应用十分广泛,尤其是在Linux平台。
gzip能力:
当Gzip压缩到一个纯文本数据时,效果是非常明显的,大约可以减少70%以上的数据大小。
gzip作用:
网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是Gzip与搜索引擎的抓取工具有着更好的关系。例如 Google就可以通过直接读取gzip文件来比普通手工抓取更快地检索网页。
HTTP协议中关于压缩传输的规定(原理)
第一:
客户端向服务器请求头中带有:Accept-Encoding:gzip, deflate 字段,向服务器表示,客户端支持的压缩格式(gzip或者deflate),如果不发送该消息头,服务器是不会压缩的。
第二:
服务端在收到请求之后,如果发现请求头中含有Accept-Encoding字段,并且支持该类型的压缩,就对响应报文压缩之后返回给客户端,并且携带Content-Encoding:gzip消息头,表示响应报文是根据该格式压缩过的。
第三:
客户端接收到响应之后,先判断是否有Content-Encoding消息头,如果有,按该格式解压报文。否则按正常报文处理。
在Feign技术中应用GZIP压缩
只配置Feign请求-应答的GZIP压缩
在交互数据量级不够的时候,看不到压缩内容。这里只开启Feign请求-应答过程中的GZIP,也就是浏览器-Application Client之间的请求应答不开启GZIP压缩。在全局配置文件中,使用下述配置来实现Feign请求-应答的GZIP压缩:
feign:
compression:
request:
enabled: true //开启请求压缩
mime-types: text/xml,application/xml,application/json
min-request-size: 1024 //设置请求大小,1024kb以上开始压缩
response:
enabled: true //响应压缩
useGzipDecoder: true //响应解码
9.超时时间配置
不配置默认超过1秒调用就会超时
feign:
hystrix:
enabled: false #关闭降级
client:
config:
#提供方的服务名,为default时则是通用调用设置
seata-storage-service:
#指的是建立连接所用的时间,适用于网络正常的情况下,两端连接所用的时间 毫秒
connectTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间 毫秒
readTimeout: 5000
二、参数调用示例
1.get请求
路径参数
调用者controller代码
OpenFeign接口
@FeignClient(value="nacos-payment-provider")
public interface FeignTool {
@GetMapping(value = "/payment/nacos/path/{id}/{name}")
String getPath(@PathVariable("id") Integer id,@PathVariable("name")String name);
}
被调用服务controller
@GetMapping(value = "/payment/nacos/path/{id}/{name}")
public String getPath(@PathVariable("id") Integer id,@PathVariable("name")String name) {
return "id:" + id+","+"name:"+name;
}
基本类型参数
调用者controller代码
@GetMapping("/payment/nacos/nfp")
public String nfp(){
return feighTool.normalFormParam("钢铁侠",33);
}
OpenFeign接口
/**
* 表单类型参数传递,基本类型
* */
@GetMapping("/payment/nacos/nfp") //即使与服务方法的参数名一致,也必须有name = ""
String normalFormParam(@RequestParam(name = "name") String name, @RequestParam(name = "age") Integer age);
被调用服务controller
@GetMapping("/payment/nacos/nfp")
String normalFormParam(String name, Integer age){
return "name:"+name+","+"age"+age;
}
集合类型参数
调用者controller代码
@GetMapping("/payment/nacos/hash")
HashMap<String,String> hashParam(){
HashMap<String,String> h = new HashMap();
h.put("1","one");h.put("2","two");h.put("3","three");
return feighTool.hashParam(h);
}
OpenFeign接口
@GetMapping("/payment/nacos/hash")
HashMap<String,String> hashParam(@SpringQueryMap HashMap<String,String> h);
被调用服务controller
@GetMapping("/payment/nacos/hash")
HashMap<String,String> hashParam(@RequestParam HashMap<String,String> h){
System.out.println(h);
return h;
}
自定义类型参数,User为自定义类型
调用者controller代码
@GetMapping("/payment/nacos/user")
User userParam(){
User u = new User();
u.setAge(26);
u.setName("wangziyu");
return feighTool.userParam(u);
}
OpenFeign接口
@GetMapping("/payment/nacos/user")
User userParam(@SpringQueryMap User u);
被调用服务controller
@GetMapping("/payment/nacos/user")
User userParam(User u){
System.out.println(u);
return u;
}
2.post请求
@RequestBody,基本类型
调用者controller代码
@GetMapping("/payment/nacos/str")
public String strBody(){
return feighTool.strBodyParam("success");
}
OpenFeign接口
@PostMapping("/payment/nacos/str")
String strBodyParam(@RequestBody String s);//此处可以不加@RequestBody,不加注解默认就是@RequestBody
被调用服务controller
@PostMapping("/payment/nacos/str")
String strBodyParam(@RequestBody String s){
return s;
}
@RequestBody,集合类型
调用者controller代码
//HashMap
@GetMapping("/payment/nacos/map")
public HashMap<String,String> mapBody(){
HashMap<String,String> h = new HashMap();
h.put("1","one");h.put("2","two");h.put("3","three");
return feighTool.mapBodyParam(h);
}
OpenFeign接口
@PostMapping("/payment/nacos/map")
HashMap<String,String> mapBodyParam(@RequestBody HashMap<String,String> h);//此处可以不加@RequestBody,不加注解默认就是@RequestBody
被调用服务controller
@PostMapping("/payment/nacos/map")
HashMap<String,String> mapBodyParam(@RequestBody HashMap<String,String> h){
return h;
}
@RequestBody,自定义类型
调用者controller代码
//自定义Entity类型
@GetMapping("/payment/nacos/rb")
public User restBody(){
User u = new User();
u.setAge(22);
u.setName("wzy");
return feighTool.reqBodyParam(u);
}
OpenFeign接口
@PostMapping("/payment/nacos/rb")
User reqBodyParam(@RequestBody User u); //此处可以不加@RequestBody,不加注解默认就是@RequestBody
被调用服务controller
@PostMapping("/payment/nacos/rb")
User reqBodyParam(@RequestBody User u){
System.out.println(u);
return u;
}
三、负载均衡
旧版OpenFeign集成了Ribbon,可使用如下配置:
@Configuration
public class FeignConfiguration {
/**
* 配置随机的负载均衡策略
* 特点:对所有的服务都生效
*/
@Bean
public IRule loadBalancedRule() {
return new RandomRule();
}
}
并可以关闭ribbon的负载均衡:
spring:
application:
name: consumer-name
cloud:
loadbalancer:
# 关闭Ribbon的负载均衡器
ribbon:
enabled: false
新版springCloud已不再集成Ribbon,需要使用spring自带的loadbalancer,默认轮询
1.引入pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2.写一个自定义的负载均衡配置类
spring自带的loadbalancer
只有两种策略,随机策略RandomLoadBalancer
和 轮询策略RoundRobinLoadBalancer
,可以自定义策略
特别注意此配置类不要加@Configuration
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
public class CustomLoadBalancerConfiguration {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
/**随机策略负载均衡*/
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);
/**轮询策略负载均衡*/
//return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);
}
}
3.主启动类配置开启
OpenFeign要调用哪个服务,就将哪个服务的名字作为name的值
//单项指定
@LoadBalancerClient(name = "nacos-payment-provider",configuration = CustomLoadBalancerConfiguration.class)
//多项指定
@LoadBalancerClients(
value = {
@LoadBalancerClient(name = "nacos-payment-provider",configuration = CustomLoadBalancerConfiguration.class),
@LoadBalancerClient(name = "nacos-payment-provider",configuration = CustomLoadBalancerConfiguration.class),
},defaultConfiguration = CustomLoadBalancerConfiguration.class
)
4.单配置开启
@FeignClient(value = "CONSUL-TEST")
@Component
@LoadBalancerClient(name = "CONSUL-TEST",configuration = LoadBalancedConfig.class)
public interface FeignService {
@LoadBalanced
@GetMapping("/consul/hello")
String sayHello();
@GetMapping("/consul/hello")
String sayHello2();
}
四、注解参数
@FeignClient
注解是 Spring Cloud OpenFeign 的核心部分,用于声明一个远程 HTTP 服务的客户端接口。下面是一些常用的参数和它们的功能:
-
name 或 value:
- 必需的。这是客户端的名称,用于创建 Ribbon 负载均衡器(如果使用的话)。通常,这也会被用作服务发现中的服务ID。
@FeignClient(name = "billing-service")
-
url:
- 可选的。用于指定请求的基础 URL。如果指定了此项,Feign 将直接指向该 URL,而忽略服务发现。如果同时指定了
name
和url
,url
可以用于开发或测试环境,而name
则用于通过服务发现找到服务。
@FeignClient(name = "billing-service", url = "https://api.billing.example.com")
- 可选的。用于指定请求的基础 URL。如果指定了此项,Feign 将直接指向该 URL,而忽略服务发现。如果同时指定了
-
contextId:
- 可选的。如果您定义了多个同名的
FeignClient
,可以用contextId
来区分不同的实例。每个上下文ID代表一个独立的Feign客户端配置。
@FeignClient(contextId = "billingClient", name = "billing-service")
- 可选的。如果您定义了多个同名的
-
configuration:
- 可选的。用于指定一个或多个配置类,这些类可以包含Feign的配置信息,如编码器、解码器、拦截器等。
@FeignClient(name = "billing-service", configuration = CustomFeignConfig.class)
-
fallback:
- 可选的。用于定义一个类,该类实现了
@FeignClient
接口,并处理回退逻辑,如在远程服务调用失败时返回默认值或进行其他操作。
@FeignClient(name = "billing-service", fallback = BillingServiceFallback.class)
- 可选的。用于定义一个类,该类实现了
-
fallbackFactory:
- 可选的。用于定义一个工厂类,该工厂类实现
FallbackFactory<T>
接口,用于创建 fallback 实例。这个参数常用于需要访问导致回退的具体原因(比如异常)时。
@FeignClient(name = "billing-service", fallbackFactory = BillingServiceFallbackFactory.class)
- 可选的。用于定义一个工厂类,该工厂类实现
-
path:
- 可选的。定义所有请求的基本路径。这个基路径会被添加到
@FeignClient
接口中定义的每一个@RequestMapping
路径前面。
@FeignClient(name = "billing-service", path = "/api")
- 可选的。定义所有请求的基本路径。这个基路径会被添加到
-
decode404:
- 可选的。如果设置为 true,Feign 将会把 404 响应解码成数据而不是抛出
FeignException
。
@FeignClient(name = "billing-service", decode404 = true)
- 可选的。如果设置为 true,Feign 将会把 404 响应解码成数据而不是抛出
-
primary:
- 可选的。指示这个客户端是否是主要的。这可以解决自动装配时的冲突。
@FeignClient(name = "billing-service", primary = true)
这些参数可以帮助你定制化@FeignClient
的使用,使其适应不同的场景和需求。