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

文章目录

  • 前言
  • [进阶用法 - 日志](#进阶用法 - 日志)
  • [进阶用法 - 超时控制](#进阶用法 - 超时控制)
  • [进阶用法 - 配置文件](#进阶用法 - 配置文件)
  • [进阶用法 - 重试机制](#进阶用法 - 重试机制)
  • 进阶用法-拦截器
  • [进阶用法 - Fallback](#进阶用法 - Fallback)

前言

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

进阶用法 - 日志

配置文件

java 复制代码
logging:
  level:
    com.qf.feign: debug

配置类

java 复制代码
@Configuration
public class BeanConfig {

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

测试类

java 复制代码
@SpringBootTest
public class LoadBalancerTest {
    @Autowired
    private TestFeignClient testFeignClient;

    @Test
    void Test(){
        String details = testFeignClient.getDetails();
        System.out.println("details = " + details);
    }
}

打印openfeign相关日志

进阶用法 - 超时控制

连接超时默认10秒,读取超时默认60秒

通过让商品服务接口休眠(也可以在商品服务中打断点)超过60秒,来查看订单服务的报错信息

js 复制代码
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 out
	at 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

也可以在配置文件中配置

yml 复制代码
spring:
  cloud:
    openfeign:
      client:
        config:
          # 默认配置
          default:
            logger-level: full
            connect-timeout: 1000
            read-timeout: 2000

进阶用法 - 配置文件

单个配置文件中配置太多属性会很乱,因此可以写多个配置文件,在主配置文件中引入

添加application-feign.yml配置文件,专门用于配置openfeign相关属性

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

在主配置文件中加入

yml 复制代码
spring:
  profiles:
    active: prod
    include: feign

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

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

进阶用法 - 重试机制

配置类中加入

java 复制代码
@Configuration
public class BeanConfig {
    ...
    //超时重试
    @Bean
    Retryer retryer(){
        //进入
        return new Retryer.Default();
    }
}

↓源码

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

参数说明:

当第一次超时后,间隔100毫秒进行第二次请求,如果没有返回则在之前基础上time1.5发送第三次请求,如果没有返回则在time 1.5*1.5毫秒发送第四次请求,总共发送五次,最长间隔时间为1秒

商品服务中让接口进行Thread.sleep(10000),在日志中可以看到商品服务接口被调用了5次

js 复制代码
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客户端生效,如订单服务)

java 复制代码
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
import java.util.UUID;

@Component
public class XTokenRequestInterceptor implements RequestInterceptor {

    /**
     * 请求拦截器
     * @param template 请求模板
     */
    @Override
    public void apply(RequestTemplate template) {
        System.out.println("XTokenRequestInterceptor ....... ");
        template.header("X-Token", UUID.randomUUID().toString());
    }
}

配置文件

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

进阶用法 - Fallback

注意:此功能需要整合 Sentinel 才能实现

如果没有设置兜底返回,如当关闭商品服务会直接报错。

相关代码

兜底回调

java 复制代码
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 {
    @Override
    public 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;
    }
}
java 复制代码
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依赖,所以发生报错时兜底回调并没有发生。

加入依赖

xml 复制代码
<!--        熔断器-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

配置文件开启熔断

yml 复制代码
feign:
  sentinel:
    enabled: true

此时关闭商品服务,调用订单服务接口


相关推荐
qq_256247051 分钟前
如何系统性打造高浏览量视频号内容
后端
码界奇点1 分钟前
基于Spring Boot与Vue.js的连锁餐饮点餐系统设计与实现
vue.js·spring boot·后端·毕业设计·源代码管理
ZePingPingZe4 分钟前
深入理解网络模型之Spring Cloud微服务通信、Socket、HTTP与RPC
网络协议·spring cloud·rpc·dubbo
源代码•宸11 分钟前
Golang原理剖析(逃逸分析)
经验分享·后端·算法·面试·golang··内存逃逸
叫码农就行24 分钟前
spring cloud 笔记
java·笔记·spring cloud
WZTTMoon28 分钟前
Spring Boot 为何不推荐使用@Autowired
java·spring boot·spring
计算机毕设指导634 分钟前
基于微信小程序的奶茶店点餐系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea
昊坤说不出的梦40 分钟前
互联网大厂Java面试实录:核心技术栈深度解析与业务场景落地
java·大数据·spring boot·微服务·ai·技术栈·互联网面试
毕设源码-赖学姐1 小时前
【开题答辩全过程】以 基于SpringBoot的电脑商城管理系统为例,包含答辩的问题和答案
spring boot·后端·电脑
Coder_Boy_1 小时前
基于SpringAI的在线考试系统-成绩管理功能实现方案
开发语言·前端·javascript·人工智能·spring boot