Spring Cloud Feign
Spring Cloud Feign
介绍:
Feign 能通过注解来实现远程调用。能够帮助我们节省很多远程调用的代码
Feign 使用了Ribbon
只需要在服务调用者中使用就行了
OpenFeign是spring基于Feign开发的spring融合版
核心思想:
无感知远程HTTP调用请求
写个案例
步骤
- 服务消费者添加Feign依赖;
- 创建业务层接口,添加
@FeignClient
注解声明需要调用的服务;- 业务抽象方法使用 SpringMVC注解配置服务地址及参数;
- 启动类加载
@EnableFeignClients
注解激活Feign 组件。
加载依赖包
加载依赖
- spring-cloud-starter-netflix-eureka-client
- spring-cloud-starter-openfeign
- spring-boot-starter-web
- org.projectlombok lombok
- spring-boot-starter-test
构建项目
- ShopApplication 中添加@EnbaleFeignClients注解 开启Feign
- 创建ProductService接口并添加@FeignClient注解
- 编写
List<Product> getProducts()
方法并使用SpringMVC注解@GetMapping("/product/list")
远程调用 - 在controller中调用看看
- application.yml中按照常規eureka配置即可
调用接口
1 | GET http://localhost:18480/shop/byid?id=331 |
Feign负载均衡
Feign基于Ribbon做了负载均衡算法
全局负载均衡配置
课程中的Loadbalancer可能过时了用了没用看官方的内容
spring-cloud-starter-openfeign
支持spring-cloud-starter-loadbalancer
. 但是,作为一个可选的依赖项,如果您想使用它,您需要确保将其添加到您的项目中
1 |
|
局部配置
与之前是一样的 但仍3.0.4仍然不成功
在yml中配置
1 | service-provider: # 服务名 |
带有参数的请求
请求
1 |
|
这里会报错:
No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no proper
某些属性是空的找不到无法正常序列化。
在Model上加入以上注解解决这个问题
1
消费者关键代码
1
2
Product getProductById( String id);提供者关键代码
正常接口
1
2
3
4
5
6
7
8
9
10
public HttpEntity getProductByCode( String id){
try {
Product product = productRepository.getById(id);
return new HttpEntity<>(product);
} catch (Exception e) {
e.printStackTrace();
return HttpEntity.EMPTY;
}
}
可以用 @PathVariable 标签设定参数
post传参
post的参数在请求体中
提供者关键代码
1
2
3
4
5
6
7
8
public HttpEntity<Product> saveProduct( Product product){
product.setName(product.getName()+"_"+serverPort);
product=productRepository.save(product);
HttpEntity<Product> httpEntity = new HttpEntity(product);
return httpEntity;
}消費者关键代码
1
2
3
Product saveProduct( Product product);
必须用@RequestBody 来读取请求体中的内容
Gzip 压缩
降低网络传输量
谷歌可以直接读取gzip
配置Gzip
全局和局部的配置的区别。
局部是关于请求到service的,全局会从相关服务一直到浏览器都进项gzip压缩
默认情况是没有启用gzip的
谷歌浏览器告诉我们他是支持gzip的
局部配置
1 | #Feign gzip 压缩 |
全局配置
1 | server: |
返回也支持了
http性能提升
在feign中通过连接池来降低负载提升性能
每次请求建立都需要三次握手,四次挥手为了降低性能开销我们使用连接池方式。
Feign的HTTP客户端支持三种框架,HttpURLConnection、HttpClient、OkHttp;默认使用HttpURLConnection(JDK自带的不支持连接池)
推荐使用HttpClient
启用httpClient
导入依赖
org.apache.httpcomponents httpclient 4.5.11
必须要用httpclient才能正常调用,因为原生不支持
io.github.openfeign feign-httpclient 10.7.4
1
2
3
4
5
6
7
8
9
10<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.11</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.7.4</version>
</dependency>修改配置文件
1
2
3feign:
httpclient:
enabled: true #开启httpClient
Get RequestBody传递对象参数
服務提供方配置
pom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign </artifactId>
<version>${openfeign.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.11</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.7.4</version>
</dependency>yml
1
2
3feign:
httpclient:
enabled: true # 默認是開啓的关键代码
1
2
3
4
5
6
7
8
public Product findShop( Product product){
Optional<Product> productOptional = productRepository.findById(product.getCode());
if(productOptional.isPresent()){
return productOptional.get();
}
return null;
}
消费者
pom yml和服务方想用
关键代码 java
1
2
Product findByProduct( Product product);
性能调优状态查看
在服务消费者中添加一个logback.xml文件
新能调优,超时设置
1 | feign: |
新版本的Feign: 已经没有再用ribbon了
Feign的雪崩处理
- 首先搭建一个与Shop相同的环境
- 有ProductService并且使用@FeignService注解调用
- 添加一个ProductConntroller来调用Product并测试成功
依赖引用
1 | <dependencies> |
配置文件
1 | server: |
构建一个feign的调service
创建一个service使用FeignClient注解进行调用
用REST风格的注解调用远端接口
在Application中使用
@EnableFeignClients
在
application.yml
中加入circuitbreaker开启的注解1
2
3feign:
circuitbreaker:
enabled: true
雪崩处理例子
修改
@FeignClient
注解1
@FeignClient(name = "eurekademo-service-product" , fallback = ProductServiceFallback.class)
创建ProductServiceFallback 并且继承ProductService并实现
必须引用spring-cloud-starter-netflix-hystrix
再关闭product引用并且调用就可以访问到兜底方法了
关键问题解决!!!!
在新版本中比如3.0.4必须要引用spring-cloud-starter-netflix-hystrix
才能正常回退。
并且需要开启ciruitbreaker
1 | feign: |
通过工厂回调(记录日志)
指定调用
在ProductService的FeignClient注解中加入参数fallbackFactory=ProductServiceFallbackFactory.class
编写Factory代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58package org.akachi.eurekademo.order.service.impl.fallback.factory;
import lombok.extern.slf4j.Slf4j;
import org.akachi.eurekademo.order.service.ProductService;
import org.akachi.eurekademo.product.model.Product;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @Author akachi
* @Email zsts@hotmail.com
* @Date 2021/11/26 0:09
*/
public class ProductServiceFallbackFactory implements FallbackFactory<ProductService> {
public ProductService create(Throwable cause) {
return new ProductService() {
public List<Product> getProducts() {
log.error("fallback getProducts"+cause);
cause.printStackTrace();
Product product = new Product();
List<Product> productList = new ArrayList();
productList.add(product);
product.setName("兜底数据");
product.setCode("-1");
return productList;
}
public Product getProductById(String id) {
log.error("fallback getProductById"+cause);
cause.printStackTrace();
Product product = new Product();
product.setName("兜底数据");
product.setCode("-1");
return product;
}
public List<Product> getProductByCodes(List<String> ids) {
log.error("fallback getProductByCodes"+cause);
cause.printStackTrace();
Product product = new Product();
List<Product> productList = new ArrayList();
productList.add(product);
product.setName("兜底数据");
product.setCode("-1");
return productList;
}
};
}
}
资料
spring cloud docs:https://spring.io/projects/spring-cloud-openfeign
https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/
feign的注解和调用方法参考文档: https://github.com/OpenFeign/feign
bilibili课程: https://www.bilibili.com/video/BV1pv411776G?p=6&spm_id_from=pageDriver
spring-loadbalancer:https://spring.io/guides/gs/spring-cloud-loadbalancer/
-
修改配置参考