当前位置: 首页 > news >正文

Spring Cloud Alibaba快速入门03-OpenFeign进阶用法

文章目录

  • 前言
  • 进阶用法 - 日志
  • 进阶用法 - 超时控制
  • 进阶用法 - 配置文件
  • 进阶用法 - 重试机制
  • 进阶用法-拦截器
    • 请求拦截器
  • 进阶用法 - Fallback


在这里插入图片描述

前言

前文介绍了OpenFeign的基本用法,而本文重点内容为OpenFeign的进阶用法,包括日志配置、超时控制、重试机制、拦截器、兜底回调等。

进阶用法 - 日志

在这里插入图片描述
配置文件

logging:level:com.qf.feign: debug

配置类

@Configuration
public class BeanConfig {@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
}

测试类

@SpringBootTest
public class LoadBalancerTest {@Autowiredprivate TestFeignClient testFeignClient;@Testvoid Test(){String details = testFeignClient.getDetails();System.out.println("details = " + details);}
}

打印openfeign相关日志
在这里插入图片描述

进阶用法 - 超时控制

在这里插入图片描述
连接超时默认10秒,读取超时默认60秒
在这里插入图片描述
通过让商品服务接口休眠(也可以在商品服务中打断点)超过60秒,来查看订单服务的报错信息

2025-09-11T22:57:59.629+08:00 DEBUG 38868 --- [qf-service-order] [nio-8080-exec-3] com.qf.feign.ProductFeignClient          : [ProductFeignClient#getProductById] ---> GET http://qf-service-product/product/11 HTTP/1.1
2025-09-11T22:57:59.629+08:00 DEBUG 38868 --- [qf-service-order] [nio-8080-exec-3] com.qf.feign.ProductFeignClient          : [ProductFeignClient#getProductById] ---> END HTTP (0-byte body)
2025-09-11T22:58:59.650+08:00 DEBUG 38868 --- [qf-service-order] [nio-8080-exec-3] com.qf.feign.ProductFeignClient          : [ProductFeignClient#getProductById] <--- ERROR SocketTimeoutException: Read timed out (60020ms)
2025-09-11T22:58:59.650+08:00 DEBUG 38868 --- [qf-service-order] [nio-8080-exec-3] com.qf.feign.ProductFeignClient          : [ProductFeignClient#getProductById] java.net.SocketTimeoutException: Read timed outat java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:244)at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:284)at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:343)at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:827)at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:762)at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1688)at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589)at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:529)at feign.Client$Default.convertResponse(Client.java:111)at feign.Client$Default.execute(Client.java:107)at org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(LoadBalancerUtils.java:56)at org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(LoadBalancerUtils.java:91)at org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient.execute(FeignBlockingLoadBalancerClient.java:134)at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:100)at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:70)at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:99)at jdk.proxy2/jdk.proxy2.$Proxy71.getProductById(Unknown Source)at com.qf.service.impl.OrderServiceImpl.createOrder(OrderServiceImpl.java:31)at com.qf.controller.OrderController.createOrder(OrderController.java:23)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.base/java.lang.reflect.Method.invoke(Method.java:568)at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:281)at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:482)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720)at com.qf.controller.OrderController$$SpringCGLIB$$0.createOrder(<generated>)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.base/java.lang.reflect.Method.invoke(Method.java:568)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)at java.base/java.lang.Thread.run(Thread.java:833)

以上日志中可以看到feign调用60秒后报错java.net.SocketTimeoutException: Read timed out
也可以在配置文件中配置

spring:cloud:openfeign:client:config:# 默认配置default:logger-level: fullconnect-timeout: 1000read-timeout: 2000

进阶用法 - 配置文件

单个配置文件中配置太多属性会很乱,因此可以写多个配置文件,在主配置文件中引入
添加application-feign.yml配置文件,专门用于配置openfeign相关属性

spring:cloud:openfeign:client:config:# 默认配置default:logger-level: fullconnect-timeout: 1000read-timeout: 2000# 指定调用商品服务配置qf-service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000

在主配置文件中加入

spring:profiles:active: prodinclude: feign

openfeign客户端的名称主要可以用属性contextId来配置,不写的话会取value值配置。

@FeignClient(value = "qf-service-product",contextId = "qf-service-product") // feign客户端
public interface ProductFeignClient {...
}

进阶用法 - 重试机制

在这里插入图片描述
配置类中加入

@Configuration
public class BeanConfig {...//超时重试@BeanRetryer retryer(){//进入return new Retryer.Default();}
}

↓源码

public static class Default implements Retryer {...public Default() {this(100L, TimeUnit.SECONDS.toMillis(1L), 5);}...
}

参数说明:
当第一次超时后,间隔100毫秒进行第二次请求,如果没有返回则在之前基础上time1.5发送第三次请求,如果没有返回则在time1.5*1.5毫秒发送第四次请求,总共发送五次,最长间隔时间为1秒
商品服务中让接口进行Thread.sleep(10000),在日志中可以看到商品服务接口被调用了5次

2025-02-23 18:36:10 id:22
2025-02-23 18:36:16 id:22
2025-02-23 18:36:21 id:22
2025-02-23 18:36:26 id:22
2025-02-23 18:36:32 id:22

进阶用法-拦截器

在这里插入图片描述

请求拦截器

在配置文件中设置拦截器(对指定feign客户端生效,如订单服务)

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
import java.util.UUID;@Component
public class XTokenRequestInterceptor implements RequestInterceptor {/*** 请求拦截器* @param template 请求模板*/@Overridepublic void apply(RequestTemplate template) {System.out.println("XTokenRequestInterceptor ....... ");template.header("X-Token", UUID.randomUUID().toString());}
}

配置文件

spring:cloud:openfeign:client:config:# 默认配置default:logger-level: fullconnect-timeout: 1000read-timeout: 2000# 指定调用商品服务配置qf-service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000request-interceptors:- com.qf.interceptor.XTokenRequestInterceptor

进阶用法 - Fallback

注意:此功能需要整合 Sentinel 才能实现
在这里插入图片描述
如果没有设置兜底返回,如当关闭商品服务会直接报错。
在这里插入图片描述
相关代码

兜底回调

import com.qf.feign.ProductFeignClient;
import com.qf.entity.Product;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;@Component
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getProductById(Long id) {System.out.println("兜底回调....");Product product = new Product();product.setId(id);product.setPrice(new BigDecimal("0"));product.setProductName("未知商品");product.setNum(0);return product;}
}
import com.qf.entity.Product;
import com.qf.feign.fallback.ProductFeignClientFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;//填写需要远程调用的服务
@FeignClient(value = "qf-service-product", fallback = ProductFeignClientFallback.class) // feign客户端
public interface ProductFeignClient {//mvc注解的两套使用逻辑//1、标注在Controller上,是接受这样的请求//2、标注在FeignClient上,是发送这样的请求@GetMapping("/product/{id}")Product getProductById(@PathVariable("id") Long id);
}

此时因为没有加入sentinel依赖,所以发生报错时兜底回调并没有发生。
加入依赖

<!--        熔断器--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>

配置文件开启熔断

feign:sentinel:enabled: true

此时关闭商品服务,调用订单服务接口
在这里插入图片描述



文章转载自:

http://Iw3QeYuO.qwrqg.cn
http://YiU4eMw1.qwrqg.cn
http://1CAQhWEu.qwrqg.cn
http://3NHrnPO6.qwrqg.cn
http://61NPSjuB.qwrqg.cn
http://z1hVA0tm.qwrqg.cn
http://9VlVF22U.qwrqg.cn
http://WjqduT9F.qwrqg.cn
http://My0foTG7.qwrqg.cn
http://8gIB14op.qwrqg.cn
http://pR1MikGD.qwrqg.cn
http://BDQwGZER.qwrqg.cn
http://MpPVzXzX.qwrqg.cn
http://CwcWWOGP.qwrqg.cn
http://MITuyIln.qwrqg.cn
http://41GSJJ98.qwrqg.cn
http://Ir4Ryfd4.qwrqg.cn
http://rAdjzorC.qwrqg.cn
http://522JCjNZ.qwrqg.cn
http://l2iU8Xne.qwrqg.cn
http://hXi8MPMH.qwrqg.cn
http://NrNGx7wi.qwrqg.cn
http://SQxm6HQV.qwrqg.cn
http://zdQmbxDj.qwrqg.cn
http://7cUPjasF.qwrqg.cn
http://afU8ddQf.qwrqg.cn
http://ue7tqrEZ.qwrqg.cn
http://oeXjrrke.qwrqg.cn
http://lxm54mit.qwrqg.cn
http://CRQ4Eq5C.qwrqg.cn
http://www.dtcms.com/a/377931.html

相关文章:

  • 【PyTorch】多对象分割
  • npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚
  • NodeJS 8 ,从 0 到 1:npm 包发布与更新全流程指南( 含多场景适配与踩坑总结 )
  • Debian 系统上安装与配置 MediaMTX
  • 【PyTorch训练】准确率计算(代码片段拆解)
  • 【Linux】线程池——详细讲解
  • Linux epoll 机制的核心控制函数——`epoll_ctl`
  • 粒子群优化(PSO)算法详解:从鸟群行为到强大优化工具
  • 从两分钟到毫秒级:一次真实看板接口性能优化实战(已上线)
  • Java入门级教程17——利用Java SPI机制制作验证码、利用Java RMI机制实现分布式登录验证系统
  • 【Redis】常用数据结构之List篇:从常用命令到典型使用场景
  • 掌握单元测试的利器:JUnit 注解从入门到精通
  • 【Vue2手录05】响应式原理与双向绑定 v-model
  • spring项目部署后为什么会生成 logback-spring.xml文件
  • Java 日期字符串万能解析工具类(支持多种日期格式智能转换)
  • 在VS2022的WPF仿真,为什么在XAML实时预览点击 ce.xaml页面控件,却不会自动跳转到具体代码,这样不方便我修改代码,
  • 【数组】区间和
  • Qt 基础编程核心知识点全解析:含 Hello World 实现、对象树、坐标系及开发工具使用
  • 解决推理能力瓶颈,用因果推理提升LLM智能决策
  • 【大前端】常用 Android 工具类整理
  • Gradle Task的理解和实战使用
  • 强大的鸿蒙HarmonyOS网络调试工具PageSpy 介绍及使用
  • C++/QT 1
  • 软件测试用例详解
  • 【ROS2】基础概念-进阶篇
  • 三甲地市级医院数据仓湖数智化建设路径与编程工具选型研究(上)
  • 利用Rancher平台搭建Swarm集群
  • BRepMesh_IncrementalMesh 重构生效问题
  • VRRP 多节点工作原理
  • 运行 Ux_Host_HUB_HID_MSC 通过 Hub 连接 U 盘读写不稳定问题分析 LAT1511