Feign 与 OpenFeign
Spring Cloud OpenFeign 并不是独立的技术。它底层基于 Netflix Feign,Netflix Feign 是 Netflix 设计的开源的声明式 WebService 客户端,用于简化服务间通信。Netflix Feign 采用“接口+注解”的方式开发,通过模仿 RPC 的客户端与服务器模式(CS),采用接口方式开发来屏蔽网络通信的细节。OpenFeign 则是在 Netflix Feign 的基础上进行封装,结合原有 Spring MVC 的注解,对 Spring Cloud 微服务通信提供了良好的支持。使用 OpenFeign 开发的方式与开发 Spring MVC Controller 颇为相似。
下面讲OpenFeign的使用方法。
服务提供方
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置
spring:
application:
name: warehouse-service #应用/微服务名字
cloud:
nacos:
discovery:
server-addr: 192.168.31.102:8848 #nacos服务器地址
username: nacos #用户名密码
password: nacos
server:
port: 80
可被调用的服务
@RestController
public class WarehouseController {
@GetMapping("/stock")
public Stock getStock(Long skuId){
/* code */
return stock;
}
}
服务调用方
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
OpenFeign 为了保证通信高可用,底层也是采用 Ribbon 实现负载均衡,其原理与 Ribbon+RestTemplate 完全相同,只不过相较 RestTemplate,OpenFeign 封装度更高罢了。
添加启用注解
@SpringBootApplication
**@EnableFeignClients** //启用OpenFeign
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
@EnableFeignClients
用于启用OpenFeign
配置
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 192.168.31.102:8848
username: nacos
password: nacos
server:
port: 80
这里只需配置Nacos即可
创建OpenFeign的通信接口与响应对象
**@FeignClient("warehouse-service")**
public interface WarehouseServiceFeignClient {
@GetMapping("/stock")
public Stock getStock(@RequestParam("skuId") Long skuId);
}
这里就是定义我们要调用的服务的接口,方法名,参数,路由什么的都要对应。
@FeignClient
注解里面就填要调用的微服务名。参数值 warehouse-service 为服务提供者 ID,这一项必须与 Nacos 注册 ID 保持一致。在 OpenFeign 发送请求前会自动在 Nacos 查询 warehouse-service 所有可用实例信息,再通过内置的 Ribbon 负载均衡选择一个实例发起 RESTful 请求,进而保证通信高可用。
这里的@GetMapping/@PostMapping
和以前我们在写控制器时经常使用的 @GetMapping 或者 @ PostMapping 不同,OpenFeign 的客户端使用这些注解的含义是:OpenFeign 向服务提供者 warehouse-service 的 stock 接口**发起 Get 请求。**不得不说这个方式和Dubbo还是很像的,
@RequestParam,该注解说明方法参数与请求参数之间的映射关系。
消费者调用
@RestController
public class OrderController {
//利用@Resource将IOC容器中自动实例化的实现类对象进行注入
**@Resource
private WarehouseServiceFeignClient warehouseServiceFeignClient;**
@GetMapping("/create_order")
public Map createOrder(Long skuId , Long salesQuantity){
//查询商品库存,像调用本地方法一样完成业务逻辑。
Stock stock = warehouseServiceFeignClient.getStock(skuId);
/* code */
return result;
}
}
@Resource
注入被调用服务的接口就可以像调用本地方法一样使用了。
完整过程
1.在第一次访问 WarehouseServiceFeignClient 接口时,Spring 自动生成接口的实现类并实例化对象。
2.当调用 getStock() 方法时,Ribbon 获取 warehouse-service 可用实例信息,根据负载均衡策略选择合适实例。
3.OpenFeign 根据方法上注解描述的映射关系生成完整的 URL 并发送 HTTP 请求,如果请求方法是 @PostMapping,则参数会附加在请求体中进行发送。
4.warehouse-service 处理完毕返回 JSON 数据,消费者端 OpenFeign 接收 JSON 的同时反序列化到 Stock 对象,并将该对象返回。
生产环境 OpenFeign 的配置事项
如何更改 OpenFeign 默认的负载均衡策略
前面提到在 OpenFeign 使用时默认引用 Ribbon 实现客户端负载均衡。如果设置 Ribbon 的负载均衡策略,其实配置方式其实与之前 Ribbon+RestTemplate 方案完全相同,只需在 application.yml 中调整微服务通信时使用的负载均衡类即可。
复制代码
warehouse-service: #服务提供者的微服务ID
ribbon:
#设置对应的负载均衡类
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
开启默认的 OpenFeign 数据压缩功能
在 OpenFeign 中,默认并没有开启数据压缩功能。但如果服务间单次传递数据超过 1K 字节,强烈推荐开启数据压缩功能。默认 OpenFeign 使用 Gzip 方式压缩数据,对于大文本通常压缩后尺寸只相当于原始数据的 10%~30%,这会极大提高带宽利用率。但有一种情况除外,如果应用属于计算密集型,CPU 负载长期超过 70%,因数据压缩、解压缩都需要 CPU 运算,开启数据压缩功能反而会给 CPU 增加额外负担,导致系统性能降低,这是不可取的。
复制代码
feign:
compression:
request:
# 开启请求数据的压缩功能
enabled: true
# 压缩支持的MIME类型
mime-types: text/xml,application/xml, application/json
# 数据压缩下限 1024表示传输数据大于1024 才会进行数据压缩(最小压缩值标准)
min-request-size: 1024
# 开启响应数据的压缩功能
response:
enabled: true
替换默认通信组件
OpenFeign 默认使用 Java 自带的 URLConnection 对象创建 HTTP 请求,但接入生产时,如果能将底层通信组件更换为Apache HttpClient
、OKHttp
这样的专用通信组件,基于这些组件自带的连接池,可以更好地对 HTTP 连接对象进行重用与管理。作为 OpenFeign 目前默认支持 Apache HttpClient 与 OKHttp 两款产品。这里以OKHttp配置方式为例。
- 引入 feign-okhttp 依赖包。
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>11.0</version>
</dependency>
- 在应用入口,利用 Java Config 形式初始化 OkHttpClient 对象。
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
//Spring IOC容器初始化时构建okHttpClient对象
@Bean
public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
//读取超时时间
.readTimeout(10, TimeUnit.SECONDS)
//连接超时时间
.connectTimeout(10, TimeUnit.SECONDS)
//写超时时间
.writeTimeout(10, TimeUnit.SECONDS)
//设置连接池
.connectionPool(new ConnectionPool())
.build();
}
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
- 在 application.yml 中启用 OkHttp。
feign:
okhttp:
enabled: true
至此,我们已将OpenFeign的默认通信对象从URLConnection调整为OKHttp,至于替换为HttpClient组件的配置思路是基本相同的。
如果需要了解OpenFeign更详细的配置选项,可以访问Spring Cloud OpenFeign的官方文档进行学习。
https://docs.spring.io/spring-cloud-openfeign/docs/2.2.6.RELEASE/reference/html/