SpringCloud实战---第十三篇: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天然支持负载均衡。
小结
- OpenFeign使用接口+注解的方式来调用远程服务(类似于一种映射配置)
- 在启动类上使用@EnableFeignClients声明OpenFeign客户端。
- 在接口上使用@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)注解来声明是远程调用,其中value跟的是服务名。
- 在接口中编写与对应的远程服务Controller对应的RequestMapping接口相同的参数和回调,然后声明接口地址即可完成映射。
- 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可以灵活的开启日志配置,配合我们开发和线上进行调试。
- 点赞
- 收藏
- 关注作者
 
             
           
评论(0)