【Spring Cloud】声明性REST客户端:Feign

Spring Cloud Feign ——fallback 服务降级

  • 1. Feign 简介
  • 2. Feign 的基础使用
    • 2.1 普通 HTTP 请求
    • 2.2 Feign 远程调用上传文件接口

1. Feign 简介

Feign 是一个声明式的 HTTP 客户端,它简化了编写基于 REST 的服务间通信代码的过程。在 Spring Cloud 中,Feign 扮演着重要的角色,它具有可插入注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器解码器Spring Cloud增加了对Spring MVC注释的支持,并使用Spring Web中默认使用的HttpMessageConverters。Spring Cloud 集成RibbonEureka或者Nacos 注册中心 以在使用 Feign 时提供负载均衡的http 客户端。

Feign 特性介绍:

  • 声明式 REST 客户端
    Feign 允许开发者使用接口和注解的方式定义对远程 REST 服务的调用,而不需要关心底层的 HTTP 请求和响应处理。在 Feign 中,可以通过接口方法的定义来描述远程服务的各种操作,包括 URL、请求方法、参数等信息。
  • 集成负载均衡
    通过整合 Ribbon 负载均衡器,Feign 可以自动实现对指定服务的负载均衡调用。这使得在服务提供者有多个实例的情况下,Feign 可以根据负载均衡策略选择合适的服务实例进行调用。
  • 支持多种请求方法
    Feign 支持各种 HTTP 请求方法,如 GETPOSTPUTDELETE 等,从而使得对远程服务的调用变得非常灵活。
  • 动态 URL 和参数绑定
    使用 Feign,可以将参数绑定到 URL 模板中,并将动态的数据传递给远程服务。同时,Feign 也支持将参数绑定到请求体中,以便进行 POSTPUT 请求。
  • 集成 Hystrix 容错机制
    结合 Spring Cloud 中的 Hystrix 断路器,Feign 可以提供对远程服务调用的容错能力,包括超时、断路器等功能,从而增强了服务调用的可靠性。
  • 易于集成
    在 Spring Cloud 应用程序中,Feign 与其他组件(如 EurekaZuul 等)无缝集成,通过简单的依赖配置和注解即可快速启用,并且无需额外的繁琐配置。

总之,Spring Cloud Feign 提供了一种简洁而优雅的方式来定义和调用 REST 服务,它简化了服务间通信的过程,提高了开发效率,为构建微服务架构的应用程序提供了便利的支持。

2. Feign 的基础使用

搭建一个 SpringCloud 的 Demo,包含生产者和消费者。 都是普通的 web 服务,其中 消费者 比生产者多了 Feign 的依赖。

        <!-- SpringCloud Openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

并且在启动类上添加注解:@EnableFeignClients
如果配置了fallbackFactory降级,则还需要引入依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

然后在启动类上添加注解:@EnableHystrix,并且添加开启服务降级的配置:

feign:
  hystrix:
    enabled: true

2.1 普通 HTTP 请求

其中生产者提供一个POST 的接口:/student/queryList 查询数据库中 student 表的数据。

@RestController
@RequestMapping("/student")
public class StudentController {

    @Resource
    private IStudentService studentService;

    @GetMapping("/queryList")
    public ApiR queryList(){
        List<Student> studentList = studentService.list();
        return ApiR.ok().data(studentList);
    }
}

消费者使用 Feign 远程调用这个查询列表的接口:

首先新建一个 @FeignClient 注解的接口

import com.lin.common.config.FeignSupportConfig;
import com.lin.common.constant.ServiceNameConstants;
import com.lin.common.vo.ApiR;
import com.lin.consumer.feign.fallback.RemoteStudentServiceFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author linmengmeng
 * @since 2023/11/12 14:12
 */
@FeignClient(contextId = "RemoteStudentService", name = ServiceNameConstants.PROVIDER_SERVICE
        , configuration = FeignSupportConfig.class, fallbackFactory = RemoteStudentServiceFallback.class)
public interface RemoteStudentService {

    @GetMapping ("/student/queryList")
    ApiR queryList();
}

我这里将生产者和消费者都注册到 Nacos 上,所以这里可以直接配置name = ServiceNameConstants.PROVIDER_SERVICE 通过生产者的服务名,直接调用对方的接口。

并配置了降级回调 fallbackFactory = RemoteStudentServiceFallback.class,降级操作是实现了上面定义的接口,并输出具体的异常信息;

import com.lin.common.vo.ApiR;
import com.lin.consumer.feign.RemoteStudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;

/**
 * @author linmengmeng
 * @since 2023/11/12 14:22
 */
@Slf4j
@Component
public class RemoteStudentServiceFallback implements FallbackFactory<RemoteStudentService> {
    @Override
    public RemoteStudentService create(Throwable cause) {
        log.error("RemoteStudentServiceFallback error : {}", cause.getMessage());
        return () -> {
            log.error("sayHello error 接口调用异常");
            return ApiR.fail();
        };
    }
}

添加一个测试请求接口,调用上面的 feign 接口:

import cn.hutool.json.JSONUtil;
import com.lin.common.vo.ApiR;
import com.lin.common.vo.R;
import com.lin.consumer.feign.RemoteStudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 测试
 * @author linmengmeng
 * @since 2023/11/8 14:18
 */
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @Resource
    private RemoteStudentService remoteStudentService;

    @GetMapping("/sayHello")
    public R sayHello() {
        log.info("sayHello。。。。。。");
        ApiR apiR = remoteStudentService.queryList();
        log.info("接口调用结果-apiR:{}", JSONUtil.toJsonStr(apiR));
        return R.ok();
    }
}

先启动消费者,然后使用 Postman 调用消费者的 sayHello接口,可以看到,这个接口里面调用了Feign的远程接口,这时候生产者没启动,服务接口queryList肯定会掉不通的,按照原来 OkHTTP 的调用,远程接口异常,会将异常传递到接口调用方。经过上面的配置,我们来调用接口看下:
在这里插入图片描述
可以看到,接口正常响应了,接着看下消费者的日志:

2023-11-12 22:18:11.504  INFO [io-37002-exec-1] [] c.l.consumer.controller.TestController   [29] : sayHello。。。。。。
2023-11-12 22:18:12.030  WARN [reakerFactory-1] [] o.s.c.l.core.RoundRobinLoadBalancer      [97] : No servers available for service: cloud-feign-provider
2023-11-12 22:18:12.033  WARN [reakerFactory-1] [] .s.c.o.l.FeignBlockingLoadBalancerClient [103] : Load balancer does not contain an instance for the service cloud-feign-provider
2023-11-12 22:18:12.065 ERROR [reakerFactory-1] [] c.l.c.f.f.RemoteStudentServiceFallback   [18] : RemoteStudentServiceFallback error : [503] during [POST] to [http://cloud-feign-provider/student/queryList] [RemoteStudentService#queryList()]: [Load balancer does not contain an instance for the service cloud-feign-provider]
2023-11-12 22:18:12.072 ERROR [reakerFactory-1] [] c.l.c.f.f.RemoteStudentServiceFallback   [20] : sayHello error 接口调用异常
2023-11-12 22:18:12.204  INFO [io-37002-exec-1] [] c.l.consumer.controller.TestController   [31] : 接口调用结果-apiR:{"code":500,"message":"系统繁忙,请稍后再试!","data":{"changeLog":"","detail":{},"releaseTime":"2023-11-12 22:18:12"}}

可以看到,在接口调用成功后,调用Feign远程接口时,打印了两行 Warn 日志,提示我们生产者服务未找到,然后打印了我们的降级服务里面的error日志,并且我们用postman请求的接口正常响应了。

这就跟我们之前使用 OkHttp 远程调用接口有区别了,这里虽然上游服务异常,但是并不影响我们这边的调用,对于消费者来说,自身有个闭环的逻辑,不会将异常传递到本身,我们的业务逻辑中可以正常获取到降级服务的结果及日志。

接着分别启动生产者的服务,再次调用消费者的接口:

2023-11-12 22:31:50.722  INFO [io-37002-exec-2] [] c.l.consumer.controller.TestController   [29] : sayHello。。。。。。
2023-11-12 22:31:51.312  INFO [io-37002-exec-2] [] c.l.consumer.controller.TestController   [31] : 接口调用结果-apiR:{"code":200,"message":"成功","data":[{"id":"001","name":"Tom","age":19,"createTime":"2023-11-12T21:19:15"},{"id":"002","name":"Mary","age":18,"createTime":"2023-11-12T21:19:39"}]}

可以看到,接口正常响应了,数据也拿到了。

2.2 Feign 远程调用上传文件接口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/136907.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何从零开始手写一个消息中间件(从宏观角度理解消息中间件的技术原理)

如何从零开始手写一个消息中间件&#xff08;从宏观角度理解消息中间件的技术原理&#xff09; 什么是消息中间件消息中间件的作用逐一拆解消息中间件的核心技术消息中间件核心技术总览IOBIONIOIO多路复用AIOIO多路复用详细分析selectpollepoll Java中的IO多路复用 协议序列化消…

【算法每日一练]-快速幂,倍增,滑动窗口(保姆级教程 篇1) #麦森数 #青蛙跳

之前是考试准备&#xff0c;所以有几天没更新&#xff0c;今天开始继续更新 目录 快速幂模板 题目&#xff1a;麦森数 思路&#xff1a; 题目&#xff1a;青蛙跳 思路&#xff1a; 快速幂模板 #include <bits/stdc.h> #define ll long long using namespa…

.net在使用存储过程中IN参数的拼接方案,使用Join()方法

有时候拼接SQL语句时&#xff0c;可能会需要将list中的元素都加上单引号&#xff0c;并以逗号分开&#xff0c;但是Join只能简单的分开&#xff0c;没有有单引号&#xff01; 1.第一种拼接方案 List<string> arrIds new List<string>(); arrIds.Add("aa&qu…

JavaScript_动态表格_删除功能

1、动态表格_删除功能 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>动态表格_添加和删除功能</title><style>table{border: 1px solid;margin: auto;width: 100%;}td,th{text-align: …

杂记 | 使用FRP搭建内网穿透服务(新版toml配置文件,搭配反向代理食用)

文章目录 01 需求与回顾02 下载程序包03 编辑.toml文件3.1 编辑frps.toml3.2 编辑frpc.toml 04 启动服务4.1 启动服务端4.2 启动客户端 05 配置反向代理&#xff08;可选&#xff09;06 windows设置为默认启动&#xff08;可选&#xff09;6.1 创建启动脚本6.2 设置为开机自启 …

【Java 进阶篇】Java与JQuery选择器:解锁前端开发的魔法大门

在前端开发的世界中&#xff0c;选择器是我们与HTML文档进行互动的钥匙&#xff0c;而Java和JQuery则为我们提供了强大的工具&#xff0c;使得前端开发不再是一个艰深的谜题。本篇博客将围绕Java与JQuery选择器展开&#xff0c;深入解析选择器的奥秘&#xff0c;为你打开前端开…

你一定要学会的Java语法 -- 【继承】

书接上回&#xff0c;我们已经学完了类和对象&#xff0c;今天内容可能有一点难&#xff0c;相信自己能跨过这道坎。 目录 一. 继承 1.什么是继承 2. 继承的概念 3. 继承的语法 4.父类成员访问 子类和父类成员变量同名 子类和父类成员方法同名 5.super关键字 6.子类构…

003、Nvidia Jetson Nano Developer KIT(b01)-深度学习环境配置

之——深度学习环境 杂谈 网上到处淘金&#xff0c;pytorch、opencv、torchvision。 正文 1.各种依赖库 1.1 pytorch的底层依赖库 sudo apt install build-essential make cmake cmake-curses-gui -ysudo apt install git g pkg-config curl -ysudo apt install libatlas-ba…

Java图像编程之:Graphics

一、概念介绍 1、Java图像编程的核心类 Java图像编程的核心类包括&#xff1a; BufferedImage&#xff1a;用于表示图像的类&#xff0c;可以进行像素级的操作。Image&#xff1a;表示图像的抽象类&#xff0c;是所有图像类的基类。ImageIcon&#xff1a;用于显示图像的类&a…

计算机中丢失msvcr120.dll文件怎么修复?找不到msvcr120.dll五种完美修复方案

今天我想和大家分享的是关于“msvcr120.dll丢失的问题的5个解决方法”。在我们日常的工作生活中&#xff0c;或许大家都曾遇到过这样的问题&#xff0c;那么&#xff0c;了解它的解决方法是非常必要的。 首先&#xff0c;让我们来了解一下msvcr120.dll是什么文件。简单来说&am…

“艾迪-东软杯”第六届武汉理工大学新生程序设计竞赛

A.Capoos Acronym Zero 题目描述 yz 和他的朋友 ea 和 zech 一起养了一群 Capoo。 这些 Capoo 非常聪明&#xff0c;但不知道为什么&#xff0c;它们并没有从三人那里学到怎么写算法题&#xff0c;而是出于某种原因开始研究语言学&#xff0c;并发明了一套自己的暗语。这门暗语…

二分图判定和二分图最大匹配

1.二分图的定义 二分图是一种特殊的无向图&#xff0c;它的节点可以被划分为两个互不相交的集合&#xff0c;使得同一集合中的任意两个节点之间没有边相连&#xff0c;而不同集合中的节点之间都有边相连。 换句话说&#xff0c;如果一个无向图可以被划分为两个集合&#xff0…

Keil文本对齐

摘要&#xff1a;通常我们写代码的时候&#xff0c;尤其是缩进和{}的使用&#xff0c;很多都需要自己手动去调整&#xff0c;如果有一个自动格式化代码的工具&#xff0c;每次编辑完代码&#xff0c;然后一键给将代码格式化&#xff0c;即省时又美观。为了解决这个问题&#xf…

面向对象高级

本期对应知识库&#xff1a;&#xff08;持续更新中&#xff01;&#xff09; 面向对象高级 (yuque.com) ​​​​​​​尚硅谷_宋红康_对象内存解析.pptx static 适用于公用变量 开发中&#xff0c;变量 经常把一些常量设置为静态static 例如 PI 方法 经常把工具类中的方…

Deepsort项目详解

一、目标追踪整体代码 代码目录如下图所示&#xff1a; 、 追踪相关代码&#xff1a; 检测相关代码和权重 调用 检测 和 追踪的代码&#xff1a; 首先代码分为三个部分&#xff1a; 目标追踪的相关代码和权重目标检测相关代码和权重&#xff0c;这里用的是yolov5.5目标检…

Thinkphp8 - 连接多个数据库

// 数据库连接配置信息connections > [mysql > [// 数据库类型type > mysql,// 服务器地址hostname > 127.0.0.1,// 数据库名database > thinkphp,// 用户名username > env(DB_USER, root),// 密码password >…

layui 表格(table)合计 取整数

第一步 开启合计行 是否开启合计行区域 table.render({elem: #myTable, url: ../baidui/, page: true, cellMinWidth: 100,totalRow:true,cols: [[ //表头//{ type: checkbox },{ type: checkbox,totalRowText: "合计" },//合计行区域{ field: id, align: center,…

【0基础学Java第九课】-- 抽象类和接口

9. 抽象类和接口 9.1 抽象类9.1.1 抽象类概念9.1.2 抽象类语法9.1.3 抽象类的特性9.1.4 抽象类的作用 9.2 接口9.2.1 接口的概念9.2.2 语法规则9.2.3 接口使用9.2.4 接口特性9.2.5 实现多个接口9.2.6 接口的继承9.2.9 抽象类和接口的区别 9.3 Object类9.3.1 获取对象方法9.3.1 …

基于springboot实现驾校管理系统项目【项目源码】计算机毕业设计

基于springboot实现驾校管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#xff0…

小H靶场学习笔记:DC-2

DC-2 Created: November 10, 2023 3:01 PM Tags: WordPress, git提权, rbash逃逸 Owner: 只会摸鱼 靶场过程 信息收集 扫描存活主机&#xff0c;找到靶机ip&#xff1a;192.168.199.131&#xff08;本机是192.168.199.129&#xff09; 扫描端口开放协议 发现有80端口和77…