SpringCloud微服务(八)——OpenFeign服务调用

news2025/2/24 6:55:03

OpenFeign服务调用

SpringCloud

github官网:https://github.com/spring-cloud/spring-cloud-openfeign

Feign是一个声明式的Web Service客户端。它的出现使开发Web Service客户端变得很简单。使用Feign只需要创建一个接口加上对应的注解,比如:FeignClient注解。Feign有可插拔的注解,包括Feign注解和JAX-RS注解。Feign也支持编码器和解码器,Spring Cloud Open Feign对Feign进行增强支持Spring MVC注解,可以像Spring Web一样使用HttpMessageConverters等。

Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用Feign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。RPC请求,对内RPC,对外Restful。

功能可插拔的注解支持,包括Feign注解和JAX-RS注解。支持可插拔的HTTP编码器和解码器(Gson,Jackson,Sax,JAXB,JAX-RS,SOAP)。支持Hystrix和它的Fallback。支持Ribbon的负载均衡集成了Ribbon,默认轮询。支持HTTP请求和响应的压缩。灵活的配置:基于 name 粒度进行配置支持多种客户端:JDK URLConnection、apache httpclient、okhttp,ribbon)支持日志支持错误重试url支持占位符可以不依赖注册中心独立运行

Feign作用:

Feign旨在使编写Java Http客户端变得更容易。前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实规下,我们只需要创建一个借口并使用注解的方式来配置它(Dao接口的Mapper注解,类似,这里是Feign注解),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

Feign与OpenFeign的区别:

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

OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解@RequestMapping。OpenFeign的@FeginClent可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理方式产生实现类,实现类中做负载均简并调用其他服务。

OpenFeign使用

面向接口

cloud-payment-service服务提供者controller:

    /**
     * 查询
     * http://localhost:8001/payment/get/31
     *
     * @param id
     * @return
     */
    @GetMapping(value = "payment/get/{id}")
    public ResponseResult getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);
        log.info("*****查询结果: " + payment);
        if (payment != null) {
            return new ResponseResult(200, "查询成功,serverPort:" + serverPort, payment);
        }
        return new ResponseResult(444, "没有对应记录,查询ID:" + id, null);
    }

    // 超时测试
    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout() {
        try {
            // 暂停3秒钟
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }

**服务提供者需要ribbon依赖/eureka客户端依赖,并且注入ribbon负载均衡算法Bean。**不然报错没有ribbon负载均衡。

新建对应服务提供者的feign模块,不用启动类和配置yml,不是微服务。

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

创建feign接口,该接口跟服务提供者的controller一样,除了名字,就是controller的接口,加上@FeignClient(value = "cloud-payment-service") 注解,value是服务提供者的服务名字

/**
 * @author wzq
 * @create 2020-02-19 23:59
 */
@Component
@FeignClient(value = "cloud-payment-service") //对应服务的名字
//@RequestMapping(value = "/content")
public interface PaymentFeign {

    /**
     * 根据id查询
     *
     * @param id
     * @return
     */
    @GetMapping(value = "payment/get/{id}")
    ResponseResult getPaymentById(@PathVariable("id") Long id);

    /**
     * 模拟feign超时
     *
     * @return
     */
    @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeout();
}

另外微服务调用feign接口

在该微服务中添加openfeign依赖,启动类加上@EnableFeignClients(basePackages = {"feign接口的包名"})启动feign调用,可以多个包。

    @Resource
    private PaymentFeign paymentFeign;

    ResponseResult<List<Content>> categoryresut = paymentFeign.getPaymentById(Long.valueOf(id));

OpenFeign携带参数调用

服务消费方,feign调用其他服务,如果有token等权限参数,需要拦截携带过去。

too many bytes written问题

feign调用需要服务器提供者ribbon负载均衡,security拦截feign服务调用设置请求头需要去掉Content-Length,不然报错too many bytes written,以为是fegin请求参数大小问题,结果不是,服务之间调用需要携带一些用户信息之类的,所以实现了Feign的RequestInterceptor拦截器复制请求头,复制的时候是所有头都复制的,可能导致Content-length长度跟body不一致. 所以只需要判断如果是Content-length就跳过。https://blog.csdn.net/qq_39986681/article/details/107138740

代码如下:

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * Title:feign添加token
 * Description:调用其它服务的feign接口前,拦截请求,添加token
 * 把当前用户的请求头封装给下一个微服务,feign调用之前拦截
 * @author WZQ
 * @version 1.0.0
 * @date 2021/3/30
 */
@Configuration
public class FeignInterceptor implements RequestInterceptor {

    // feign底层是RequestTemplate
    @Override
    public void apply(RequestTemplate requestTemplate) {
        try {
            //使用RequestContextHolder工具获取request相关变量
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                //取出request
                HttpServletRequest request = attributes.getRequest();
                //获取所有头文件信息的key
                Enumeration<String> headerNames = request.getHeaderNames();
                if (headerNames != null) {
                    while (headerNames.hasMoreElements()) {
                        //头文件的key
                        String name = headerNames.nextElement();
                        // 跳过 content-length,不会feign调用出错 too many bytes written
                		if (name.equals("content-length")){
                    		continue;
                		}
                        //头文件的value
                        String values = request.getHeader(name);
                        //将令牌数据添加到头文件中
                        requestTemplate.header(name, values);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

feign设置请求参数大小:

# feign请求携带参数数量,设置大点,避免too many bytes written (2ms)
feign:
  compression:
    request:
      min-request-size: 4096

OpenFeign超时设置

服务提供者:

    // 超时测试
    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout() {
        try {
            // 暂停3秒钟
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }

feign接口:

/**
 * @author wzq
 * @create 2020-02-19 23:59
 */
//@Component
@FeignClient(value = "cloud-payment-service") //对应服务的名字
public interface PaymentFeign {

    /**
     * 模拟feign超时
     *
     * @return
     */
    @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeout();
}

调用:

    @Resource
    private PaymentFeign paymentFeign;

    @GetMapping(value = "/consumer/payment/feign/timeout")
    public String paymentFeignTimeout() {
        // openfeign-ribbon, 客户端一般默认等待1秒钟
        return paymentFeignService.paymentFeignTimeout();
    }

由于服务提供者controller中设置停留3秒,其他微服务feign调用该接口就会超时请求,默认openfeign-ribbon客户端只等待1秒钟

在这里插入图片描述

为了避免这样的超时情况,我们需要设置feign客户端(调用feign接口的微服务)中超时控制,yml添加:

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

这里超时设置成5秒,连接也是5秒。

OpenFeign日志处理

调用feign接口的微服务,如果需要知道feign调用的情况,可以通过打印日志查看。

openfeign提供了日志打印功能。

Logger有四种类型:NONE(默认)BASICHEADERSFULL,通过注册Bean来设置日志记录级别。NONE(默认)不需要注入。

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

在调用feign接口的微服务中,设置config:

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

/**
 * OpenFeignClient配置
 *
 * @author zzyy
 * @create 2020/3/6 18:02
 **/
@Configuration
public class FeignConfig {

    /**
     * feignClient配置日志级别
     *
     * @return
     */
    @Bean
    public Logger.Level feignLoggerLevel() {
        // 请求和响应的头信息,请求和响应的正文及元数据
        return Logger.Level.FULL;
    }
}

并在yml中配置:

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

调用,打印如下:

在这里插入图片描述

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

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

相关文章

基于java+springboot+mybatis+vue+elementui的人职匹配推荐系统

项目介绍 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;对于人职匹配推荐系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了人职匹配推荐系统&#xff0c;它彻底改变…

分享一下前几个月我做的超炫的登录页面

先给大家看看登录页面的效果演示 这个登录页面分为三个部分&#xff08;页面切换&#xff1a;连续按五次V&#xff0c;大小写都可以&#xff09; 第一个&#xff08;最初的鱼儿游动页面&#xff09; 登录、切换页面、和鱼儿游动这个页面的代码就不放在这里了&#xff0c;这个虽…

RabbitMQ 入门案例项目

写在前面 本文不作消息队列的实现原理、异步处理优劣、rabbitmq安装说明、消息工作模式等内容分析&#xff0c;只讲述rabbitmq实际开发中的步骤说明&#xff0c;帮助同学快速上手体验消息队列的使用。 本文使用SpringAMQP&#xff0c;并非rabbitmq官方文档上的原生http请求连…

Jupyter notebook在超算平台上使用的详细教程

Jupyter Notebook 的本质是一个 Web 应用程序&#xff0c;便于创建和共享文学化程序文档&#xff0c;支持实时代码&#xff0c;数学方程&#xff0c;可视化和 markdown。 用途包括&#xff1a;数据清理和转换&#xff0c;数值模拟&#xff0c;统计建模&#xff0c;机器学习等等…

LeetCode 数据结构与算法:最大子数组和

打开我的题库&#xff0c;调为简单难度。 计算最大子数&#xff0c;直接给我难住。 报错铺满屏幕&#xff0c;凝望没有思路。 缝缝补补做出&#xff0c;击败零个用户。 翻阅评论找补&#xff0c;令我勃然大怒。 打开思维第一步&#xff0c;编写代码求数组&#xff0c; …

报错解决:Process finished with exit code -1073741819 (0xC0000005)

简单记录一下程序异常终止&#xff0c;抛出 Process finished with exit code -1073741819 (0xC0000005) 的解决方法。 一、程序中文件位置错误/缺少文件 位置错误1&#xff1a;如果使用相对路径的话&#xff0c;推荐换成绝对路径进行排查。位置错误2&#xff1a;如果使用了o…

CAN总线协议测试拓扑图

记录测试CAN总线协议&#xff0c; CAN总线目前主要应用在汽车。 记录在PC使用USB-CAN连接测试

Talk预告 | Salesforce AI研究院研究科学家徐嘉诚:文本生成中的结构化解码

本期为TechBeat人工智能社区第457期线上Talk&#xff01; 北京时间11月23日(周三)20:00&#xff0c;Salesforce AI研究院研究科学家——徐嘉诚的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “文本生成中的结构化解码”&#xff0c;届时将详细讲解…

学会用数据分析汇报工作,升职加薪指日可待

你是否每天的八小时工作时长&#xff0c;分成八瓣用&#xff0c;却仍被领导安排众多工作&#xff1f;明明做了很多事&#xff0c;领导依旧认为工作量不饱和&#xff1f;这样的现象在职场中早已司空见惯&#xff0c;不足为奇了&#xff0c;但是究其原因是什么呢&#xff1f;工作…

Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)

运行有问题或需要源码请点赞关注收藏后评论区留言私信~~~ 一、通过runOnUiThread快速操纵界面 因为Android规定分线程不能够直接操纵界面&#xff0c;所以它设计了处理程序工具&#xff0c;由处理程序负责在主线程和分线程之间传递数据&#xff0c;如果分线程想刷新界面&#…

精心整理16条MySQL使用规范,减少80%问题

1. 禁止使用select * 阿里开发规范中&#xff0c;有这么一句话&#xff1a; **select *** 会查询表中所有字段&#xff0c;如果表中的字段有更改&#xff0c;必须修改SQL语句&#xff0c;不然就会执行错误。 查询出非必要的字段&#xff0c;徒增磁盘IO和网络延迟。 2. 用小表…

小学生python游戏编程arcade----敌人精灵上方显示方框及子弹显示问题

小学生python游戏编程arcade----敌人精灵上方显示方框及子弹显示问题前言1、敌人精灵上方显示方框1.1 修改enemy_tank类1.2 引用1.3 效果图2、调整方法2.1 类方法2.2 类的引用2.3 效果图2.4 大小位置调整后3、子弹过线自动消失3.1 子弹的更新中3.2 原因查到&#xff0c;把以下代…

day11 多级缓存

day11 多级缓存 1、什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; 请求要经过 Tomcat 进行处理&#xff0c;Tomcat 的性能成为整个系统的瓶颈Red…

数字孪生助力轨道交通安保可视化应用

截至2020年12月31日&#xff0c;全国&#xff08;不含港澳台&#xff09;共有44个城市开通运营城市轨道交通线路233条&#xff0c;运营里程7545.5公里&#xff0c;车站4660座&#xff0c;完成客运量175.9亿人次&#xff0c;进站量109.1亿人次。针对轨道交通地铁站内日常监测、事…

牛客网语法篇练习分支控制(一)

1.据说智商140以上者称为天才&#xff0c;KiKi想知道他自己是不是天才&#xff0c;请帮他编程判断。输入一个整数表示一个人的智商&#xff0c;如果大于等于140&#xff0c;则表明他是一个天才&#xff0c;输出“Genius”。 while True:try:a int(input())if a >140:print…

云原生加速器企业维格表创始人陈霈霖:提供人人可用的数字化转型全新方案,真正驱动组织创新

看上去是像Excel一样的在线协同表格&#xff0c;却能把文件、表格、图片、视频、填表单等变换出各种视图&#xff0c;它能帮助你高效方便的管理各种零碎的信息和数据&#xff1b;也能根据你的想法DIY各种功能&#xff0c;5分钟即可搭建一个适合自己的文档管理系统&#xff0c;实…

C#上位机系列(1)—项目的建立

本文是讲解C#.net平台的Winform框架下的第一个内容&#xff0c;手把手介绍项目的创建方式以及一些写软件时常用的功能。之前写过一篇关于示波器的比较抽象&#xff0c;本文讲解从零开始的每一个步骤。 VS2022以及C#.net平台的Winform框架自行百度下载。 1.创建一个新的项目 …

智慧经营| 物业数字化管理系统

无论小区、公寓还是豪华区&#xff0c;总是少不了物业的身影&#xff0c;通过物业可以为住户解决许多事情&#xff0c;比如物业报事、物业维修、便民服务、送水上门、房屋租赁、投诉等&#xff0c;但小区内公告栏没人看、挨家挨户的去通知效率低、且无法全面完善管理区域内的所…

Linux操作系统~尝试自己制作并使用动静态库

目录 1.动态库和静态库到底是什么 &#xff08;1&#xff09;.静态库 vs 动态库 &#xff08;2&#xff09;.动态链接和静态链接的优劣 &#xff08;3&#xff09;.ldd指令 2.自己制作静态库 &#xff08;1&#xff09;.打包静态库 &#xff08;2&#xff09;.ar指令 3…

Java基础之《netty(4)—NIO之Channel》

一、基本介绍 1、NIO的通道类似于流&#xff0c;但有些区别 &#xff08;1&#xff09;通道可以同时进行读写&#xff0c;而流只能读或者只能写 &#xff08;2&#xff09;通道可以实现异步读写数据 &#xff08;3&#xff09;通道可以从缓冲读数据&#xff0c;也可以写数据到…