SpringCloud OpenFeign 服务接口调用

news2024/11/26 12:44:19

一、前言

        接下来是开展一系列的 SpringCloud 的学习之旅,从传统的模块之间调用,一步步的升级为 SpringCloud 模块之间的调用,此篇文章为第四篇,即介绍 Feign 和 OpenFeign 服务接口调用。

二、概述

2.1 Feign 是什么

        Feign 是一个声明式的 Web 服务客户端,让编写 Web 服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。

2.2 Feign 用途

2.2.1 Feign 能干什么

        Feign 旨在使编写 Java Http 客户端变得更容易。前面在使用 Ribbon + RestTemplate 时,利用 RestTemplate http 请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。

        所以,Feign 在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在 Feign 的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是 Dao 接口上面标注 Mapper 注解,现在是一个微服务接口上面标注一个 Feign 注解即可),即可完成对服务提供方的接口绑定,简化了使用 Spring cloud Ribbon 时,自动封装服务调用客户端的开发量。

2.2.2 Feign 集成了 Ribbon

        Feign 集成了 Ribbon 利用 Ribbon 维护了 Payment 的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与 Ribbon 不同的是,通过 feign 只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

2.3 Feign 和 OpenFeign 区别

        Feign Spring Cloud 组件中的一个轻量级 RESTful HTTP 服务客户端,Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。

        Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。需要引入的依赖如下:

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

        OpenFeign Spring Cloud Feign 的基础上支持了 SpringMVC 的注解,如 @RequesMapping 等等。OpenFeign@FeignClient 可以解析 SpringMVC @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。需要引入的依赖如下:

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

三、OpenFeign 使用步骤

3.1 新建工程

        新建一个子模块工程 cloud-consumer-feign-order80,用于展示 OpenFeign 的使用步骤。

3.2 添加依赖

        在 pom.xml 中,添加如下的依赖:

<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.springcloud</groupId>
        <artifactId>SpringCloud</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

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

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <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.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.3 添加配置文件

        在 application.yml 中添加如下的配置信息:

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

3.3 修改启动类

        需要在启动类上添加 @EnableFeignClients 注解用于开启 OpenFeign 的使用,代码如下:

package com.springcloud;

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

@SpringBootApplication
// 开启 OpenFeign 
@EnableFeignClients
public class OrderFeignMain80
{
    public static void main(String[] args)
    {
        SpringApplication.run(OrderFeignMain80.class,args);
    }
}

3.4 创建业务类

        创建业务逻辑接口 PaymentFeignService,并在接口上添加 @FeignClient 注解,代码如下所示:

package com.springcloud.service;

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

@Component
// value 值是对外暴露的服务名称
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {

    @GetMapping(value = "/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

}

        创建控制层代码 OrderFeignController,用于对外提供服务,代码如下:

package com.springcloud.controller;

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

@RestController
public class OrderFeignController {
    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
    {
        return paymentFeignService.getPaymentById(id);
    }
}

3.5 测试

        分别启动 cloud-eureka-server7001cloud-eureka-server7002cloud-provider-payment8001cloud-provider-payment8002 cloud-consumer-feign-order80 模块,然后在浏览器输入 http://localhost/consumer/payment/get/1,进行测试,不断刷新界面如下图,可以看到,OpenFeign 还默认实现了负载均衡。

3.6 小结

四、OpenFeign 超时控制

4.1 简介

        默认 Feign 客户端只等待一秒钟,但是服务端处理需要超过 1 秒钟,导致 Feign 客户端不想等待了,直接返回报错。

4.2 现象演示

        在 cloud-provider-payment8001 模块的 PaymentController 中添加一个测试方法,如下:

@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeOut()
{
	System.out.println("*****paymentFeignTimeOut from port: "+serverPort);
	//暂停几秒钟线程
	try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
	return serverPort;
}

        在 cloud-consumer-feign-order80 模块的 PaymentFeignService 中添加一个调用方法,代码如下:

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {

    @GetMapping(value = "/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

    @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeOut();

}

        在 cloud-consumer-feign-order80 模块的 OrderFeignController 中添加一个调用方法,代码如下:

@RestController
public class OrderFeignController {
    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
    {
        return paymentFeignService.getPaymentById(id);
    }

    @GetMapping(value = "/consumer/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
        return paymentFeignService.paymentFeignTimeOut();
    }
}

        分别启动 cloud-eureka-server7001cloud-eureka-server7002cloud-provider-payment8001 和 cloud-consumer-feign-order80 服务,然后在浏览器输入 http://localhost/consumer/payment/feign/timeout,进行测试,如下图,可以看到出现了超时的错误。

4.3 问题解决

        由于 OpenFeign 默认支持 Ribbon,所以只需要在 cloud-consumer-feign-order80 模块的 application.yml 中开启并配置 OpenFeign 的客户端超时控制即可,如下:

# 设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

        重启 cloud-consumer-feign-order80 模块,重新调用测试的 url 如下图:

五、OpenFeign 日志打印功能

5.1 简介

        Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign Http 请求的细节。说白了就是对 Feign 接口的调用情况进行监控和输出。

5.2 日志级别

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

5.3 配置

        在 cloud-consumer-feign-order80 模块中新建一个配置类 FeignConfig ,代码如下:

package com.springcloud.config;

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

@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

        在 application.yml 中配置日志的 Feign 客户端,因为 spring 的默认日志级别是 info,而 openFegin 打印日志需要 debug,所以需要将 spring 日志级别改为 debug,在 application.yml 中,为了只打印 openFegin 日志,可以只将 openFegin 接口的包路径设置为 dubug

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

5.4 测试

        随便调用一个测试方法,后台输出的日志如下:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux运维:深入了解 Linux 目录结构

Linux运维&#xff1a;深入了解 Linux 目录结构 一、 Linux 目录结构与 Windows之间的主要区别二、Linux根目录结构三、常见目录及其作用 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 一、 Linux 目录结构与 Windows之间的主要区别 1、根…

PXE+Kickstart无人值守安装操作系统

什么是PXE&#xff1f; PXE&#xff0c;全名Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff1b; 通过网络接口启动计算机&#xff0c;不依赖本地存储设备&#xff08;如硬盘&#xff09;或本地已安装的操作系统&#xff1b; 由Intel和Systemsoft公司于199…

2007-2021年中国省级知识产权保护指数数据

2007-2021年中国省级知识产权保护指数数据 1、时间&#xff1a;2007-2021年 2、范围&#xff1a;31省市 3、指标&#xff1a;&#xff1a;年份、省份、IPP&#xff08;知识产权保护指数&#xff09; 4、来源&#xff1a;全国知识产权发展状况报告 5、指标解释&#xff1a;…

游戏党们的福利来啦~格行5G随身WiFi,王者玩家的靠谱之选!5G随身wifi品牌推荐第一名!

作为一名资深王者荣耀玩家&#xff0c;我深知网络对于游戏的重要性。那种关键时刻网络卡顿、延迟&#xff0c;导致错失战机、输掉比赛的痛苦&#xff0c;真是让人欲哭无泪。直到我的游戏搭子给我推荐了一款格行5G随身wifi&#xff0c;简直是打开新世界的大门&#xff01; 格行…

Singularity(四)| 自定义容器

Singularity&#xff08;四&#xff09;| 自定义容器 4.1 Singularity Definition 文件 对于可复制的、高质量的容器&#xff0c;我们应该使用定义文件&#xff08;Definition File&#xff09;构建 Singularity 容器 。使用定义文件的方式可以在纯文本文件中描述容器的配置和…

考研数学|汤家凤《1800》vs 张宇《1000》,怎么选?

汤家凤的1800题和张宇的1000题都是备考数学考研的热门选择&#xff0c;但究竟哪个更适合备考呢&#xff1f;下面分享一些见解。 首先&#xff0c;让我们来看看传统习题册存在的一些问题。虽然传统习题册通常会覆盖考试的各个知识点和题型&#xff0c;但其中一些问题在于它们可…

论文阅读:Editing Large Language Models: Problems, Methods, and Opportunities

Editing Large Language Models: Problems, Methods, and Opportunities 论文链接 代码链接 摘要 由于大语言模型&#xff08;LLM&#xff09;中可能存在一些过时的、不适当的和错误的信息&#xff0c;所以有必要纠正模型中的相关信息。如何高效地修改模型中的相关信息而不影…

LeetCode 每日一题 Day 95-101

2917. 找出数组中的 K-or 值 给你一个整数数组 nums 和一个整数 k 。让我们通过扩展标准的按位或来介绍 K-or 操作。在 K-or 操作中&#xff0c;如果在 nums 中&#xff0c;至少存在 k 个元素的第 i 位值为 1 &#xff0c;那么 K-or 中的第 i 位的值是 1 。 返回 nums 的 K-o…

SpringBoot扩展篇:Spring注入 @Autowired @Resource

Spring注入 Autowired & Resource 1. 概述1.1 职责1.2 流程概述 2. Demo3. AutowiredAnnotationBeanPostProcessor注册4. 注册元数据4.1 AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition4.2 AutowiredAnnotationBeanPostProcessor#findAutowiringMe…

【NR 定位】3GPP NR Positioning 5G定位标准解读(十二)-Multi-RTT定位

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

Hive面经

hive原理 Hive 内部表和外部表的区别Hive 有索引吗运维如何对 Hive 进行调度ORC、Parquet 等列式存储的优点数据建模用的哪些模型&#xff1f;1. 星型模型2. 雪花模型3. 星座模型 为什么要对数据仓库分层&#xff1f;使用过 Hive 解析 JSON 串吗sort by 和 order by 的区别数据…

React 教程

学习主要来源 React 教程 | 菜鸟教程 React 是一个用于构建用户界面的 JAVASCRIPT 库。 React 主要用于构建 UI&#xff0c;很多人认为 React 是 MVC 中的 V&#xff08;视图&#xff09;。 React 起源于 Facebook 的内部项目&#xff0c;用来架设 Instagram 的网站&#xff0…

GSEA -- 学习记录

文章目录 brief统计学原理部分其他注意事项转录组部分单细胞部分 brief 上一篇学习记录写了ORA&#xff0c;其中ORA方法只关心差异表达基因而不关心其上调、下调的方向&#xff0c;也许同一条通路里既有显著高表达的基因&#xff0c;也有显著低表达的基因&#xff0c;因此最后…

2023年第三届中国高校大数据挑战赛第二场赛题C:用户对博物馆评论的情感分析(附上代码与详细视频讲解)

问题重述&#xff1a; 博物馆是公共文化服务体系的重要组成部分。国家文物局发布&#xff0c; 2021 年我国新增备案博物馆 395 家&#xff0c;备案博物馆总数达 6183 家&#xff0c;排名全球前列&#xff1b;5605 家博物馆实现免费开放&#xff0c;占比达 90%以上&#xff1b;…

基于Springboot的高校汉服租赁网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的高校汉服租赁网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

蓝桥杯算法错题记录-基础篇

文章目录 本文还在跟新&#xff0c;最新跟新时间3/11&#xff01;&#xff01;&#xff01; 格式一定要符合要求&#xff0c;&#xff08;输入&#xff0c;输出格式&#xff09;1. nextInt () next() nextLine() 的注意事项2 .数的幂 a^2等3.得到最大长度&#xff08;最大...&a…

Redis缓存问题详解和处理

缓存更新策略 缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库. 常见的解决方案: 缓存空对象 优点: 实现简单, 维护方便缺点: 额外的内存消耗, 可能造成短期的不一致 布隆过滤 优点: 内存占用较少(保存的是数据…

【0基础学C语言】04-常量、变量

一、数据的存储 1.数据类型 首先来看看计算机是怎么存储数据的。总的来说,计算机中存储的数据可以分为两种:静态数据和动态数据。 1> 静态数据 概念:静态数据是指一些永久性的数据,一般存储在硬盘中。硬盘的存储空间一般都比较大,现在普通计算机的硬盘都有500G左右…

Leetcode每日一题[C++]-1261.在受污染的二叉树中查找元素

题目描述 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给出一个满足下述规则的二叉树&#xff1a; root.val 0如果 treeNode.val x 且 treeNode.left ! null&#xff0c;那么 treeNode.left.val 2 * x 1如果 treeNode.val x 且 treeNode.right ! nu…

这些年背过的面试题——SpringMVC篇

1 什么是SpringMVC &#xff1f;简单介绍下你对SpringMVC的理解? SpringMVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用…