RPC 框架 openfeign 介绍和学习使用总结

news2025/1/9 5:59:57

一、基本概念

RPC

远程过程调用Remote Procedure Call)的缩写形式

Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文《Implementing remote procedure calls》对 RPC 做了经典的诠释。

RPC 是指计算机 A 上的进程,调用另外一台计算机 B 上的进程,其中 A 上的调用进程被挂起,而 B 上的被调用进程开始执行,当值返回给 A 时,A 进程继续执行。

调用方可以通过使用参数将信息传送给被调用方,而后可以通过传回的结果得到信息。而这一过程,对于开发人员来说是透明的。

openfeign 和 feign

OpenFeign 是 Spring Cloud 在 Feign 的基础上支持了SpringMVC的注解,如@RequesMapping等等。

OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

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

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

OpenFeign 的设计宗旨是简化 Java Http 客户端的开发。

FeignrestTemplate 的基础上做了进一步的封装,由其来帮助我们定义和实现依赖服务接口的定义。
在OpenFeign的协助下,我们只需创建一个接口并使用注解的方式进行配置(类似于Dao接口上面的Mapper注解)即可完成对服务提供方的接口绑定,大大简化了Spring cloud Ribbon的开发,自动封装服务调用客户端的开发量。

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

二、基本使用

依赖

依赖于springMVC 的 web 服务,或者直接使用 spring-boot 的 spring-boot-starter-web 系列基础包。
web 等基础系列包

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

feign 基本

${openfeign.version} 可以自定替换版本,这里示例用 2.2.2.RELEASE

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
			<version>${openfeign.version}</version>
		</dependency>
		<!-- okhttp openfeign远程调用依赖的HttpClient -->
		<dependency>
			<groupId>io.github.openfeign</groupId>
			<artifactId>feign-okhttp</artifactId>
			<version>${feign-okhttp.version}</version>
		</dependency>

如果出现引入后出现个别问题可以尝试去除如下

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
			<version>${openfeign.version}</version>
			<exclusions>
				<exclusion>
					<artifactId>guava</artifactId>
					<groupId>com.google.guava</groupId>
				</exclusion>
			</exclusions>
		</dependency>

服务注册中心的依赖,一般场景不需要(使用分布式场景时考虑)

<!--服务发现客户端-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>

启用

spring-boot 需要在启动类上添加注解 @EnableFeignClients
位置与 @SpringBootApplication@EnableTransactionManagement@ComponentScan 等在启动类上的注解 位置一致
例如:
在这里插入图片描述

  1. 若同时考虑分布式场景,即 cloud 自带的 eureka
    在相同的位置增加 注解 @EnableEurekaClient
    同时可以在yml 或 properties 配置如下参考
eureka:
  client:
    serviceUrl:
      #服务中心地址
      defaultZone: http://localhost:8881/eureka/,http://localhost:8882/eureka/ 
  instance:
    #显示ip地址
    prefer-ip-address: true 

超时时间设置

默认超时时间为 1s

feign:
  client:
    config:
      default:
        readTimeout: ${RPC_TIME_OUT:600000}
        connectTimeout: ${RPC_TIME_OUT:600000}

也可以配置

# OpenFeign 默认支持 ribbon
ribbon:
  # 建立连接所用的时间,两端连接所用的时间
  ReadTimeout: 6000
  # 建立连接后从服务器读取到可用资源所用时间
  ConnectTimeout: 6000

创建请求

大致可以参考如下示例:

import com.alibaba.fastjson.JSONObject;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

@FeignClient(name = "XxxxClient", url = "${xxxx.server}")
public interface XxxxClient {

    @PostMapping("/test/create")
    XxxxxResult createXxxxxxx(@RequestBody XxxxxxxRequest body,
                                        @RequestHeader MultiValueMap<String, String> header);

    @PostMapping(value = "/test/check", consumes = "multipart/form-data")
    XxxxxResult importXxxxx(@RequestPart("file") MultipartFile file, @RequestParam Long id,
                                  @RequestHeader MultiValueMap<String, String> header);

    @PostMapping("/test/config")
    XxxxxResult xxxxxxConfig(@RequestParam Long id, @RequestBody JSONObject body,
                                   @RequestHeader MultiValueMap<String, String> header);

    @PostMapping("/test/xxxxxx")
    XxxxxResult xxxxxXxxxxxxxx(@RequestParam Long id, @RequestBody JSONObject body, @RequestHeader MultiValueMap<String, String> header);

    @GetMapping("/test/xxxx/{id}")
    XxxxxResult xxxxXxxxx(@PathVariable String id, @RequestHeader MultiValueMap<String, String> header);

}

在上面的请求中添加请求头的方式

  1. 在请求注解中添加
@RequestMapping(value="/xxxxx/xxxxx",method = RequestMethod.POST,
		headers = {"Content-Type=application/json;charset=UTF-8"})
    List<String> test();
  1. 如上方直接在参数中增加,多个使用map ,也可以在单个参数前加 单个注解@RequestHeader(“xxxx”) 指定值

  2. 在方法上方使用注解

	@RequestMapping(value="/xxxx/xxxxx",method = RequestMethod.POST)
	@Headers({"Content-Type: application/json;charset=UTF-8"})
    List<String> test();
  1. 见下方拦截器中增加请求头

说明
1.其中 @FeignClient(name = “XxxxClient”, url = “${xxxxx.server}”)
url 中的 ${xxxxx.server} 为spring-boot 中 yml 或者 properties 中配置的地址,也可以直接写入地址 例如:http://localhost:8081/testapi

2.可以通过 @GetMapping@PostMapping 直接指定将要请求的方法是 GET 或者POST 等请求,同理 @RequestParam 指定普通请求入参, @RequestHeader 指定请求的请求的头内容, @PathVariable 指定路径参数,@RequestBody 指定 请求体内容, @RequestPart 指定文件类型

3.@GetMapping@PostMapping后面的路径 即为实际请求第三方或要请求的其他产品的路径

用法基本与书写普通的请求类似,具体实现通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务,只要我们指定基本的所有关键信息即可,换言之,只要知道我们要携带的信息,后续的实现写法基本固定,故此可以实现高度封装。

@SpringQueryMap注解:

spring cloud 项目使用 feign 时会发现一个问题,就是get方式无法解析对象参数
其实 feign 是支持对象传递的,但是必须是 Map 形式,而且不能为空,与spring在机制上不兼容,因此无法使用。

spring cloud 在 2.1.x版本 中提供了**@SpringQueryMap** 注解,可以传递对象参数,框架自动解析。

例如:

@GetMapping(value = "/test/xxxxxxXxxx")
    XxxxxResult xxxxXxxxXxX(@SpringQueryMap BookDto dto);

@FeignClient

@FeignClient 相关属性如下:

属性说明
name指定该类的容器名称,类似于@Service(容器名称)
url即要请求的地址,可以更改指定地址
decode404当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
configurationFeign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
fallback定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
fallbackFactory用于生成fallback类示例,通过这个属性可以实现每个接口通用容错逻辑,减少重复代码
path定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用

远程调用接口当中,一般我们称提供接口的服务为提供者,而调用接口的服务为消费者。
OpenFeign一定是用在消费者上。

feign 日志等级控制

Feign 提供了日志打印功能,我们可以通过配置不同级别来调整日志输出内容,从而了解 Feign 中 Http 请求的细节。

其实就是多了一个请求日志的输出控制方式。

日志级别

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

具体配置方式见后面的其他配置说明示例。

三、配置类

1. RequestInterceptor

可以通过自定义某一个类实现接口 RequestInterceptor(feign.RequestInterceptor) 来完成发送请求前要做的操作,例如添加统一的请求头,拼接统一参数,替换路径等等操作

例如
该接口只有一个方法,通过接口的入参可以获取当前请求的一些信息,或者修改当前请求的一些信息

@Slf4j
public class FeignBasicRequestInterceptor implements RequestInterceptor {

	public FeignBasicRequestInterceptor() {
    }

	    @Override
    public void apply(RequestTemplate template) {
    	// 可以通过获取不同的路径来确定当前请求的是那一个请求或者哪一类请求,来具体确定要执行怎样的操作
    	
        // template.feignTarget().url()    获取当前请求基本路,即@FeignClient 中的url 基础路径
        // template.url()     获取定义请求方法时 getMapping或postMapping后的地址 
        // template.method()   请求的类型 GET 还是 POST
        // template.body()  请求体,可能为空则可以 new String(template.body()) 或给与默认值
        // template.headers() 请求的头信息
        // template.header(String name, String... values) 设置添加请求头,具体可以点击类查看源码
        // template.query(String name, Iterable<String> values) 设置增加query 参数
        
    }

}

可能用到: 基础认证

template.header(HttpHeaders.AUTHORIZATION, okhttp3.Credentials.basic(ak, sk));

2. 指定配置类

即 上方 @FeignClient 属性中可以指定的配置类
不是必须的但可以指定,内部的几个类也可以按需增加,部分可以不要

MyX509TrustManager 为自定类,用于适配https 信任所有证书或者自定义,在后面提供定义的内容

import feign.Client;
import feign.Logger;
import feign.Retryer;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

import static org.apache.http.conn.ssl.SSLConnectionSocketFactory.TLS;


@Slf4j
@Configuration
class FeignConfiguration {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

	// OkHttpClient 替代原有的client,可以不替代
    @Bean
    public Client feignClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        SSLContext sslContext =
                SSLContexts.custom().loadTrustMaterial(null, (chain, authType) -> true).setProtocol(TLS).build();
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        OkHttpClient okHttpClient = new OkHttpClient.Builder().hostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .sslSocketFactory(sslSocketFactory, new MyX509TrustManager()).build();
        return new feign.okhttp.OkHttpClient(okHttpClient);
    }

    @Bean
    // 与上方加的配置类名称一致
    public FeignBasicRequestInterceptor basicAuthRequestInterceptor() {
        return new FeignBasicRequestInterceptor();
    }

    @Bean
    // 日志等级 上方日志等级中提及到的
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

    @Bean
    // 重试
    Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }

    @Bean
    // 结果解码类 new FeignResponseDecoder 为自己定义的解码类,见下方定义
    public Decoder feignDecoder() {
        return new OptionalDecoder(
                new FeignResponseDecoder(new SpringDecoder(this.messageConverters)));
    }
}

日志配置后的使用,需要在配置文件中指定某一接口或者类的等级

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

MyX509TrustManager

(可选)需要可以仿照添加

import javax.net.ssl.X509TrustManager;

/**
 * Https调用需要使用的TrustManager
 */
public class MyX509TrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
    // 什么都不做则信任所有 否则自定义内容
    }

    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
    // 什么都不做则信任所有 否则自定义内容
    }

    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }
}

3. feign结果自定义解析类

import feign.FeignException;
import feign.Response;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * feign返回结果自定义解析
 **/
@Slf4j
public class FeignResponseDecoder extends ResponseEntityDecoder implements Decoder {

    public FeignResponseDecoder(Decoder decoder) {
        super(decoder);
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        Object decode = super.decode(response, type);
        // type.getTypeName() 最上方创建请求时  定义的返回结果的toString 结果
        if (type.getTypeName().contains(XxxxxResult.class.getName())) {
            XxxxxResult result = (XxxxxResult) decode;
            // 检查返回是否为对方定义的成功码  如果不是抛出异常
            if (!"200".equals(result.getCode())) {
            // 可以使用自定义异常类 这里示例使用普通异常
                throw new Exception(result.getMessage());
            }
        }

        return decode;
    }
}

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

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

相关文章

元核云亮相金博会,智能质检助力金融合规

11月初&#xff0c;第五届中新&#xff08;苏州&#xff09;数字金融应用博览会&#xff5c;2023金融科技大会在苏州国际博览中心举办&#xff0c;围绕金融科技发展热点领域及金融行业信息科技领域重点工作&#xff0c;分享优秀实践经验&#xff0c;探讨数字化转型路径与未来发…

C# OpenCvSharp DNN HybridNets 同时处理车辆检测、可驾驶区域分割、车道线分割

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Numerics; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_D…

设备零部件更换ar远程指导系统加强培训效果

随着科技的发展&#xff0c;AR技术已经成为了一种广泛应用的新型技术。AR远程指导系统作为AR技术的一种应用&#xff0c;具有非常广泛的应用前景。 一、应用场景 气象监测AR教学软件适用于多个领域&#xff0c;包括气象、环境、地理等。在教学过程中&#xff0c;软件可以帮助学…

Day26力扣打卡

打卡记录 搜索旋转排序数组&#xff08;二分&#xff09; 链接 class Solution {int findMin(vector<int> &nums) {int left -1, right nums.size() - 1; // 开区间 (-1, n-1)while (left 1 < right) { // 开区间不为空int mid left (right - left) / 2;if…

Antd G6实现自定义工具栏

在使用g6实现知识图谱可视化中&#xff0c;产品经理提出了有关图谱操作的不少功能&#xff0c;需要放置在工具栏中&#xff0c;其中有些功能不在g6自带的功能里&#xff0c;且工具栏样式、交互效果也和官方自定义工具栏不同。那我们怎么去实现呢&#xff1f; g6官方的工具栏案例…

Azure 机器学习 - 使用自动化机器学习训练计算机视觉模型的数据架构

目录 一、用于训练的数据架构图像分类&#xff08;二进制/多类&#xff09;多标签图像分类对象检测实例分段 二、用于联机评分的数据架构输入格式输出格式图像分类&#xff08;二进制/多类&#xff09;多标签图像分类对象检测实例分段 在线评分和可解释性 (XAI) 的数据格式支持…

Linux的目录的权限

目录 目录的权限 目录的权限 1、可执行权限: 如果目录没有可执行权限, 则无法cd到目录中. 2、可读权限: 如果目录没有可读权限, 则无法用ls等命令查看目录中的文件内容. 3、可写权限: 如果目录没有可写权限, 则无法在目录中创建文件, 也无法在目录中删除文件. 上面三个权限是…

SpringBoot3+Vue3+Mysql+Element Plus完成数据库存储blob类型图片,前端渲染后端传来的base64类型图片

前言 如果你的前后端分离项目采用SpringBoot3Vue3Element Plus&#xff0c;且在没有OSS&#xff08;对象存储&#xff09;的情况下&#xff0c;使用mysql读写图片&#xff08;可能不限于图片&#xff0c;待测试&#xff09;。 耗时三天&#xff0c;在踩了无数雷后&#xff0c…

深度学习 python opencv 动物识别与检测 计算机竞赛

文章目录 0 前言1 深度学习实现动物识别与检测2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存…

如何帮助 3D CAD 设计师实现远程办公

当 3D CAD 设计师需要远程办公时&#xff0c;他们可能需要更强的远程软件&#xff0c;以满足他们的专业需求。比如高清画质&#xff0c;以及支持设备重定向、多显示器支持等功能。3D CAD 设计师如何实现远程办公&#xff1f;接下来我们跟随 Platinum Tank Group 的故事来了解一…

百度王颖:百度文库以AI创作能力突破语言边界,促进思想碰撞和文化融通

1月9日&#xff0c;2023年世界互联网大会乌镇峰会“网络传播与文明交流互鉴论坛”召开。百度副总裁、互娱和垂类平台负责人王颖出席并发表“以技术搭建跨文化交流桥梁”主题演讲。她表示&#xff0c;在大模型的加持下&#xff0c;百度各个产品都在重构&#xff0c;通过技术助力…

链表练习题

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

【数据结构】反射、枚举

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 反射、枚举 1. 反射1.1 定义1.2 反射…

建造者模式 rust和java的实现

文章目录 建造者模式介绍优点缺点使用场景 实现javarust rust代码仓库 建造者模式 建造者模式&#xff08;Builder Pattern&#xff09;使用多个简单的对象一步一步构建成一个复杂的对象。 一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。 介绍…

gird 卡片布局

场景一&#xff1a;单元格大小相等 这承载了所有 CSS Grid 中最著名的片段&#xff0c;也是有史以来最伟大的 CSS 技巧之一&#xff1a; 等宽网格响应式卡片实现 .section-content {display: grid;grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));gap: 10px; …

系列二十二、idea Live Templates

一、idea Live Templates 1.1、Java Group 1.1.1、fast fast 快速在类上添加注解Data AllArgsConstructor NoArgsConstructor Accessors(chain true) ToString(callSuper true) 1.1.2、getThreadName getThreadName快速获取当前线程的名字Thread.currentThread().getName…

故障诊断模型 | Maltab实现ELM极限学习机的故障诊断

文章目录 效果一览文章概述模型描述源码设计参考资料效果一览 文章概述 故障诊断模型 | Maltab实现ELM极限学习机的故障诊断 模型描述 在机器学习领域,我们常常需要通过训练数据来学习一个函数模型,以便在未知的数据上进行预测或分类。传统的神经网络模型需要大量的参数调整和…

54基于matlab的包络谱分析

基于matlab的包络谱分析&#xff0c;目标信号→希尔伯特变换→得到解析信号→求解析信号的模→得到包络信号→傅里叶变换→得到Hilbert包络谱&#xff0c;包络谱分析能够有效地将这种低频冲击信号进行解调提取。程序已调通&#xff0c;可直接运行。 54matlab包络谱分析信号解调…

高德地图添加信息弹窗,信息弹窗是单独的组件

//弹窗组件 <template><el-card class"box-card" ref"boxCard" v-if"showCard"><div slot"header" class"clearfix"><div class"title">{{ model.pointName }}</div><div class…

《单链表》的实现(不含哨兵位的单向链表)

目录 ​编辑 前言&#xff1a; 链表的概念及结构&#xff1a; 链表的实现&#xff1a; 1.typedef数据类型&#xff1a; 2.打印链表 &#xff1a; 3.创建新节点&#xff1a; 4.尾插 &#xff1a; 5.头插&#xff1a; 6.尾删 &#xff1a; 7.头删&#xff1a; 8.查找节…