springboot中使用Feign整合nacos,gateway进行微服务之间的调用方法

Java
408
0
0
2023-09-10
目录
  • 1、什么是Feign
  • 2、为什么使用Feign?
  • 3、如何使用Feign?
  • 3.1注册中心Nacos部署
  • 3.2部署生产者
  • 3.3 部署消费者,使用Feign调用provider方法
  • 4.ribbon负载均衡策略
  • 5.Feign传参
  • 6.Feign 性能优化
  • 7.整合gateway网关服务

1、什么是Feign

Feign 是 Spring Cloud Netflix 组件中的一个轻量级 RESTful 的 HTTP 服务客户端,实现了负载均衡和 Rest 调用的开源框架,封装了 Ribbon 和 RestTemplate,实现了 WebService 的面向接口编程,进一步降低了项目的耦合度。

Feign 内置了 Ribbon(其主要功能是提供客户端实现负载均衡算法),用来做客户端负载均衡调用服务注册中心的服务。

Feign 本身并不支持 Spring MVC 的注解,它有一套自己的注解,为了更方便的使用,Spring Cloud 孵化了 OpenFeign。

Feign 是一种声明式、模板化的 HTTP 客户端(仅在 Consumer 中使用)。

Feign 支持的注解和用法请参考官方文档:https://github.com/OpenFeign/feign 或 spring.io 官网文档

Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

2、为什么使用Feign?

1.微服务之间调用变得简单

它让微服务之间的调用变得更简单了,类似controller调用service

2.使用简单

只需要创建一个接口,然后添加注解即可使用Feign

3.简化代码

Feign默认集成了Ribbon,简化了使用Spring Cloud Ribbon负载均衡时,自动封装服务调用客户端的开发量

3、如何使用Feign?

目录及项目结构

在这里插入图片描述

子工程

<modules>
    <module>service-provider</module>
    <module>service-provider</module>
    <module>service-consumer</module>
    <module>service-gateway</module>
</modules>

注:

注册中心实例 nacos

service-provider | service-provider02 服务提供者实例

service-consumer 服务消费者

service-gateway 网关服务

3.1注册中心Nacos部署

部署nacos(略)

3.2部署生产者

1.新建maven项目,过程省略…

2.关键配置

server:
port: # 端口
 
spring:
application:
name: service-provider # 应用名称(集群下相同)
#nacos配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:

3.逻辑部分

为了检测Feign的负载均衡,所以在provide01中,将返回结果增加01后缀

/**
 * 查询商品列表
 *
 * @return
 */
@Override
public List<Product> selectProductList() {
    return Arrays.asList(
            new Product(, "华为手机01", 1, 5800D),
            new Product(, "联想笔记本01", 1, 6888D),
            new Product(, "小米平板01", 5, 2020D)
    );
}

4.部署双节点provide02

重复步骤 【1~3】,修改serverImpl逻辑,改为后缀加02

/**
 * 查询商品列表
 *
 * @return
 */
@Override
public List<Product> selectProductList() {
    return Arrays.asList(
            new Product(, "华为手机02", 1, 5800D),
            new Product(, "联想笔记本02", 1, 6888D),
            new Product(, "小米平板02", 5, 2020D)
    );
}

5.启动双节点,监控Nacos

两个生产者实例已经启动

3.3 部署消费者,使用Feign调用provider方法

1.新建maven工程,过程省略…

2.引入nacos和feign的pom依赖

<!-- nacos  依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>.9.0.RELEASE</version>
</dependency><!-- spring cloud openfeign 依赖 -->
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

3.添加配置文件

server:
port: # 端口
 
spring:
application:
name: service-consumer # 应用名称
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:

4.在服务接口层声明使用Feign

使用FeignClient注解,声明要调用的服务

// 声明需要调用的服务
@FeignClient("service-provider")
public interface ProductService

对方法使用GetMapping注解,配置需要调用的服务路由地址

// 配置需要调用的服务地址及参数
@GetMapping("/product/list")
List<Product> selectProductList();

5.方法调用

在另一个impl里调用ProductService的方法,而不用关注ProductServiceImpl里面的实现逻辑,它会远程请求生产者中controller里的方法.

在这里插入图片描述

/**
   * 根据主键查询订单
   *
   * @param id
   * @return
   */
  @Override
  public Order selectOrderById(Integer id) {
      return new Order(id, "order-", "中国", 22788D,
              productService.selectProductList());
  }

消费者controller中的方法

在这里插入图片描述

/**
 * 根据主键查询订单
 *
 * @param id
 * @return
 */
@GetMapping("/{id}")
public Order selectOrderById(@PathVariable("id") Integer id) {
    return orderService.selectOrderById(id);
}

过postman调用 localhost:9090/order/2 结果,可以看到已经成功使用Feign进行了远程调用,

并且同一个请求,返回两个provider的不同结果,由此可知Feign也实现了负载均衡

调用1

调用2

4.ribbon负载均衡策略

在消费者配置文件中修改ribbon的负载均衡策略

在这里插入图片描述

service-provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule #配置规则 重试
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略

5.Feign传参

1.Get方法

使用 @PathVariable 注解或 @RequestParam 注解接收请求参数

provider接口层ProductService.java

ProductService.java方法

/**
 * 根据主键查询商品
 *
 * @param id
 * @return
 */
Product selectProductById(Integer id);
provider实现类ProductServiceImpl.java

ProductServiceImpl.java方法

/**
 * 根据主键查询商品
 *
 * @param id
 * @return
 */
@Override
public Product selectProductById(Integer id) {
    return new Product(id, "冰箱",, 2666D);
}

provider的控制类ProductController.java

ProductController.java方法

/**
 * 根据主键查询商品
 *
 * @param id
 * @return
 */
@GetMapping("/{id}")
public Product selectProductById(@PathVariable("id") Integer id) {
    return productService.selectProductById(id);
}

provider服务中,controller使用了(@PathVariable(“id”) Integer id) 进行参数接收

consumer的接口层ProductService.java

@GetMapping("/product/{id}")
Product selectProductById(@PathVariable("id") Integer id);

consumer服务中,使用了(@PathVariable(“id”) Integer id) 进行参数接收,写法类似于在controller中定义请求方法和定义参数

consumer的接口层OrderService.java

Order getOrderById(Integer id);

consumer的接口实现类OrderServiceImpl.java

@Override
public Order getOrderById(Integer id) {
    return new Order(id, "order-", "中国", 2666D,
            Arrays.asList(productService.selectProductById(id)));
}

consumer的控制类OrderController.java

@GetMapping("selectProductById/{id}")
public Order selectProductById(@PathVariable("id") Integer id) {
    return orderService.getOrderById(id);
}

访问localhost:9090/order/selectProductById/888得到结果

在这里插入图片描述

Post方法

使用 @RequestBody 注解接收请求参数。

provider的ProductService.java

/**
 * 新增商品
 *
 * @param product
 * @return
 */
Map<Object, Object> createProduct(Product product);

provider的ProductServiceImpl.java

/**
   * 新增商品
   *
   * @param product
   * @return
   */
  @Override
  public Map<Object, Object> createProduct(Product product) {
      System.out.println(product.getProductName());
      return new HashMap<Object, Object>() {{
          put("code",);
          put("message", "新增成功");
      }};
  }

provider的ProductController.java

/**
  * 新增商品
  *
  * @param product
  * @return
  */
 @PostMapping("/save")
 public Map<Object, Object> createProduct(@RequestBody Product product) {
     return productService.createProduct(product);
 }

consumer的ProductService.java

/**
 * 新增商品
 *
 * @param product
 * @return
 */
@PostMapping("/product/save")
Map<Object, Object> createProduct(Product product);
consumer的OrderService.java

Map<Object, Object> createProduct(Product product);
consumer的OrderServiceImpl.java

@Override
public Map<Object, Object> createProduct(Product product) {
    return productService.createProduct(product);
}

consumer的OrderController.java

/**
  * 新增商品
  *
  * @param product
  * @return
  */
 @PostMapping("/save")
 public Map<Object, Object> createProduct(Product product) {
     return orderService.createProduct(product);
 }

访问http://localhost:9090/order/save 参数

id:6

productName:华为

productNum:1

productPrice:6666666

执行结果

在这里插入图片描述

在这里插入图片描述

6.Feign 性能优化

1.Gzip 压缩

gzip 是一种数据格式,采用 deflate 算法压缩数据;gzip 是一种流行的文件压缩算法,应用十分广泛,尤其是在 Linux 平台。

2.gzip 能力

当 Gzip 压缩一个纯文本文件时,效果是非常明显的,大约可以减少 70% 以上的文件大小。

3.gzip 作用

网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google 就可以通过直接读取 gzip 文件来比普通手工抓取更快地检索网页。

4.配置HTTP 连接池

4.1HTTP背景

两台服务器建立 HTTP 连接的过程是很复杂的一个过程,涉及到多个数据包的交换,很耗时间。

HTTP 连接需要的 3 次握手 4 次挥手开销很大,这一开销对于大量的比较小的 HTTP 消息来说更大。

4.2解决方案

采用 HTTP 连接池,可以节约大量的 3 次握手 4 次挥手,这样能大大提升吞吐量。

Feign 的 HTTP 客户端支持 3 种框架:HttpURLConnection、HttpClient、OkHttp;默认是 HttpURLConnection。可以通过查看源码 org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration.java 得知。

传统的 HttpURLConnection 是 JDK 自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,如果有可用的其他方案,没有必要自己去管理连接对象。

HttpClient 相比传统 JDK 自带的 HttpURLConnection,它封装了访问 HTTP 的请求头,参数,内容体,响应等等;它不仅使客户端发送 HTTP 请求变得容易,而且也方便了开发人员测试接口(基于 HTTP 协议的),既提高了开发的效率,又提高了代码的健壮性;另外高并发大量的请求网络的时候,也是用“连接池”提升吞吐量。

添加依赖

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>.7.4</version>
</dependency>

配置开启连接池

feign:
  httpclient:
    enabled: true # 开启 httpclient

使用压测工具检测单线程 10000次请求网络响应情况

图1.未配置httpclient连接池.新建连接和关闭连接占用大量时间,端口被占用无法释放.导致后来的连接无法被创建,增加程序异常几率

在这里插入图片描述

图2.配置httpClient连接池开启,第一次交互会打开连接,交互结束后连接并不关闭,下次交互就省去了建立连接的过程

在这里插入图片描述

7.整合gateway网关服务

1.搭建gateway网关服务(略)

2.增加配置

server:
  port:  #网关端口
spring:
  application:
    name: nacos-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:  #注册中心地址
      config:
        server-addr: localhost:  #配置中心地址 TODO配置中心读取不到 需要调查原因
        file-extension: yaml
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: nacos-gateway-provider
          uri: lb://service-consumer  #目标服务地址
          predicates: #断言
            - Path=/**

3.测试8001端口转发是否正常

在这里插入图片描述