SpringCloud实战---第十三篇:OpenFeign快速上手

举报
老司机张师傅 发表于 2022/07/26 23:23:43 2022/07/26
【摘要】 前言 OpenFeign也太好用了吧!!! 说起来容易做起来难,一步一步都干完!!! 学习一定要自己动手搞一搞,不能只眼会。 学习笔记是跟着尚硅谷的视频学的:传送门 关于OpenFeign前身是Feign,但是当前Feign已经停止开源维护,SpringCloud基于Feign封装了OpenFeign。OpenFeign是声明式的微服务调用,只需要编写接口和添加注解即可,因此在编码上和代码...

前言

OpenFeign也太好用了吧!!!

在这里插入图片描述

说起来容易做起来难,一步一步都干完!!!

学习一定要自己动手搞一搞,不能只眼会。

学习笔记是跟着尚硅谷的视频学的:传送门


关于OpenFeign

  • 前身是Feign,但是当前Feign已经停止开源维护,SpringCloud基于Feign封装了OpenFeign。
  • OpenFeign是声明式的微服务调用,只需要编写接口和添加注解即可,因此在编码上和代码的简易性上会给我们更大的便利。
  • OpenFeign就是在Ribbon的基础上面,封装出了一个框架。
  • 使用简单,创建一个微服务接口并且在上面使用相关的注解就可以使用啦!!!

先构建好基础工程(一篇一篇看过来的不用重新构建)

构建基础父工程:https://blog.csdn.net/weixin_43464964/article/details/121979995
Rest风格微服务:https://blog.csdn.net/weixin_43464964/article/details/121980366
传统分布式方法:https://blog.csdn.net/weixin_43464964/article/details/121999966
改造工程,抽取公共模块:https://blog.csdn.net/weixin_43464964/article/details/122000586
使用Eureka:https://blog.csdn.net/weixin_43464964/article/details/122045319
Eureka集群: https://blog.csdn.net/weixin_43464964/article/details/122046056

想偷懒的请下载;gitee上我上传的代码:
懒人传送门

基础工程构建完成的目录结构:

在这里插入图片描述
启动所有模块,访问

localhost:7001

显示如下,代表基础工程没问题
在这里插入图片描述

话不多说,立马开干

新建Feign服务调用方

OpenFeign是在微服务的调用方使用的

1. 新建Feign服务调用方

创建cloud-consumer-feign-order80模块

cloud-consumer-feign-order80

2. 添加POM依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2021</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-feign-order80</artifactId>


    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--一般基础通用配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

3. 添加application.yml

server:
  port: 80  # 本微服务端口号 80

eureka:
  client:
    register-with-eureka: false     #false表示不向注册中心注册自己。
    service-url:
      #表示Eureka的地址
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

4. 创建基础包及启动类

com.atguigu.springcloud

创建主启动类,并在主启动类上添加@EnableFeignClients注解标识开启Feign

OrderFeignMain80
package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author: Daisen.Z
 * @Date: 2021/12/24 18:39
 * @Version: 1.0
 * @Description:
 */
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain80.class,args);
    }

}

5. 编写FeignClient业务类

创建service包
在这里插入图片描述
前面我们说过,Feign是注解声明式的调用,我们使用Feign需要添加一个接口,然后给接口上添加注解来声明调用哪个微服务哪个方法。
这里我们一步步来进行构建。
首先,创建出service接口,@FeignClient()表示这个接口是使用Feign远程调用。

package com.atguigu.springcloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;

@Component
@FeignClient()
public interface PaymentFeignService {

}

在这里插入图片描述
接着,我们需要告诉Feign这个接口调用的是哪个微服务,我们要调用8001,因此把8001的服务配名配置给他。
在这里插入图片描述

@FeignClient(value = "CLOUD-PAYMENT-SERVICE")

在这里插入图片描述
然后,我们就可以开始编写接口映射了。
为了测试的方便课直观,我们把8001/8002服务的controller的getPaymentById方法粘贴过来,去掉他的方法体。
我们来解读下这块代码,首先我们使用@EnableFeignClients注解开启了OpenFeign,然后我们编写接口,并在接口上声明了@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)表示对应的是哪个微服务,接着我们和编写Controller一样编写一个参数、返回值和微服务接口一样的方法声明,这样Feign是不是就可以通过我们的注解得知该方法调用的是哪个微服务的哪个接口了。

package com.atguigu.springcloud.service;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
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;

/**
 * @Author: Daisen.Z
 * @Date: 2021/12/26 10:54
 * @Version: 1.0
 * @Description:
 */
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {

    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id);

}

6. 编写Controller

编写Controller,调用我们使用OpenFeign调用的Service

OpenFeignController
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.service.PaymentFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Author: Daisen.Z
 * @Date: 2021/12/26 11:08
 * @Version: 1.0
 * @Description:
 */
@RestController
@Slf4j
public class OpenFeignController {

    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping("/feign/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        return paymentFeignService.getPaymentById(id);
    }

}

开始测试

1. 启动以下服务

在这里插入图片描述

2. 访问地址,使用Feign调用微服务接口

http://localhost/feign/payment/get/1

在这里插入图片描述
多刷新几次,你会发现在轮询调用8001和8002,这也说明OpenFeign天然支持负载均衡。

小结

  1. OpenFeign使用接口+注解的方式来调用远程服务(类似于一种映射配置)
  2. 在启动类上使用@EnableFeignClients声明OpenFeign客户端。
  3. 在接口上使用@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)注解来声明是远程调用,其中value跟的是服务名。
  4. 在接口中编写与对应的远程服务Controller对应的RequestMapping接口相同的参数和回调,然后声明接口地址即可完成映射。
  5. OpenFeign天然支持了Ribbon负载均衡。

超时控制

既然微服务是分布式调用,包括Ribbon,包括OpenFeign本质上都是HttpClient的调用,那么就必然会面临一个问题–超时。
我们来演示以下这种情况并学习下如何做超时控制。

1.编写代码测试超时

修改8001和8002的Controller,添加一个接口,什么都不做sleep3秒钟(FeignClient默认等待时间是1秒钟),来模拟请求超时。

// 服务发现测试
@GetMapping("/payment/feign/timeout")
public String paymentFeignTimeout(){
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return serverPort;
}

在这里插入图片描述
修改cloud-consumer-feign-order80模块的PaymentFeignService,添加该接口的调用
在这里插入图片描述
修改cloud-consumer-feign-order80模块的OpenFeignController
在这里插入图片描述

2.测试超时

启动程序,访问8001端口,过三秒左右会能够正常返回

http://localhost:8001/payment/feign/timeout

访问下80端口的服务,发现会出现调用超时

localhost/consumer/payment/feign/timeout

报了个接口超时的错误
在这里插入图片描述

3.原因

出现这种超时错误的原因是Feign客户端默认只等待一秒钟,而服务端处理需要超过1秒,这样因为FeignClient端不等这么久,就会页面读取超时的错误了。

4.开启超时控制

Feign是基于Ribbon封装的,天然使用的Ribbon,所以我们通过添加Ribbon配置即可开启Feign超时控制
给feign80模块添加配置

ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

在这里插入图片描述
重启之后。再访问Feign80端口服务,会发现已经可以正常调用了。

调整默认日志级别

Feign提供默认可以设置默认日志的打印级别,方便我们的调试和线上维护。

级别 展示信息
NONE 默认的,不显示任何日志
BASIC 仅记录请求方法、URL、响应状态码及执行时间
HEADERS 除了 BASIC 中定义的信息之外,还有请求和响应的头信息
FULL 除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据

1. 开启Feign日志打印

给feign80模块添加配置bean,代表开启日志打印

package com.atguigu.springcloud.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * @Author: Daisen.Z
 * @Date: 2021/12/26 19:40
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class FeignConfig {

    @Bean
    Logger.Level feignLoggerLevel(){
        // Full(全信息)级别
        return Logger.Level.FULL;
    }

}

在这里插入图片描述

2. 修改配置文件,添加接口的详细打印级别

代表以debug级别监控PaymentFeignService的full日志


logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.atguigu.springcloud.service.PaymentFeignService: debug

在这里插入图片描述

3. 重启服务,访问接口,查看后台日志

在这里插入图片描述
打印了十分详细的日志信息,这在我们开发调试中非常使用,我们可以灵活的使用。

总结

1. OpenFeign使用接口+注解的方式来调用远程服务(类似于一种映射配置)

2. 在启动类上使用@EnableFeignClients声明OpenFeign客户端。

3. 在接口上使用@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)注解来声明是远程调用,其中value跟的是服务名。

4. 在接口中编写与对应的远程服务Controller对应的RequestMapping接口相同的参数和回调,然后声明接口地址即可完成映射。

5. OpenFeign天然支持了Ribbon负载均衡。

6. 配置Ribbon超时时间可以解决客户端和服务端超时时间不一致问题。

7. Feign可以灵活的开启日志配置,配合我们开发和线上进行调试。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。