Back
Featured image of post OpenFeign服务调用入门

OpenFeign服务调用入门

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 HttpClientOKHttp 这样的专用通信组件,基于这些组件自带的连接池,可以更好地对 HTTP 连接对象进行重用与管理。作为 OpenFeign 目前默认支持 Apache HttpClient 与 OKHttp 两款产品。这里以OKHttp配置方式为例。

  1. 引入 feign-okhttp 依赖包。
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>11.0</version>
</dependency>
  1. 在应用入口,利用 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);
    }
}
  1. 在 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/

comments powered by Disqus
一辈子热爱技术
Built with Hugo
Theme Stack designed by Jimmy
gopher