springcloud feign

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: springcloud feign

Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

添加feign 的依赖

<!-- 引入open feign 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

使用,在接口上添加注解 @FeignClient("") 进行配置

@FeignClient(value = "order-server", path = "order")
public interface OrderFeignService {
    @GetMapping("/findOrderByUserId/{id}")
    R findOrderByUserId(@PathVariable("id") Integer id);
}

在启动类中加入注解 @EnableFeignClients

@SpringBootApplication
@EnableFeignClients
public class StudyuserApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudyuserApplication.class, args);
    }
}

在UserController 调用 , 跟普通接口一样的写法。

@Autowired
private OrderFeignService orderFeignService;
@GetMapping("/findOrderByUserIdWithFeign/{id}")
public R findOrderByUserIdWithFeign(@PathVariable("id") Integer id) {
    // feign调用
    R result = orderFeignService.findOrderByUserId(id);
    return result;
}

测试,验证

spring cloud feign 的自定义配置及使用

日志配置

有时候我们遇到 Bug,比如接口调用失败、参数没收到等问题,或者想看看调用性能,就需要配置 Feign 的日志了,以此让 Feign 把请求信息输出来。

日志等级有 4 种,分别是:

NONE【性能最佳,适用于生产】:不记录任何日志(默认值)。

BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。

HEADERS:记录BASIC级别的基础上,记录请求和响应的header。

FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据

全局配置

加入配置类 FeignConfig

package com.jiuge.user.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author jiuge
 * @version 1.0
 * @date 2021/8/5 11:16
 */
@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

配置好后在yml 文件加入对应feign目录的日志级别

logging:
  level:
    com.jiuge.user.feign: debug

请求接口 http://localhost:8010/user/findOrderByUserIdWithFeign/1 测试,验证, 把日志请求信息打印出来了

2021-08-05 11:22:08.205 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] ---> GET http://order-server/order/findOrderByUserId/1 HTTP/1.1
2021-08-05 11:22:08.205 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] ---> END HTTP (0-byte body)
2021-08-05 11:22:08.562 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] <--- HTTP/1.1 200 (356ms)
2021-08-05 11:22:08.562 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] connection: keep-alive
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] content-type: application/json
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] date: Thu, 05 Aug 2021 03:22:08 GMT
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] keep-alive: timeout=60
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] transfer-encoding: chunked
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] 
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] {"msg":"success","code":0,"orders":[{"id":1,"userId":"1","commodityCode":"UT2191929213903","count":1,"amount":2}]}
2021-08-05 11:22:08.563 DEBUG 14128 --- [nio-8010-exec-1] com.jiuge.user.feign.OrderFeignService   : [OrderFeignService#findOrderByUserId] <--- END HTTP (114-byte body)
// @Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

修改OrderFeignService 接口的注解,接口头加入 configuration 注解

// feignConfig 的局部配置
@FeignClient(value = "order-server", path = "order",configuration = FeignConfig.class)
public interface OrderFeignService {
    @RequestMapping("/findOrderByUserId/{id}")
    R findOrderByUserId(@PathVariable("id") Integer id);
}

请求接口http://localhost:8010/user/findOrderByUserIdWithFeign/1测试,验证

局部配置2,可以在yml 进行配置

logging:
  level:
    com.jiuge.user.feign: debug
feign:
  client:
    config:
      order-server:
        loggerLevel: FULL

OrderFeignService 类上去除  configuration  配置


@FeignClient(value = "order-server", path = "order",configuration = FeignC

换成


@FeignClient(value = "order-server", path = "order")

测试验证

契约配置

Spring Cloud 在 Feign 的基础上做了扩展,可以让 Feign 支持 Spring MVC 的注解来调用。原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式来定义客户端也是可以的,通过配置契约来改变这个配置,Spring Cloud 中默认的是 SpringMvcContract。


修改契约配置,支持原生的配置

在FeignConfig 上添加如下内容

/**
 * 修改契约配置,支持Feign原生的注解
 * @return
 */
@Bean
public Contract feignContract() {
    return new Contract.Default();
}

修改OrderFeignService 类内容

使用原生的feign 注解 @RequestLine


// feignConfig 的局部配置
@FeignClient(value = "order-server", path = "order")
public interface OrderFeignService {
    // @RequestMapping("/findOrderByUserId/{id}")
    @RequestLine("GET /findOrderByUserId/{userId}")
    R findOrderByUserId(@PathVariable("userId") Integer userId);
}

局部配置  上面配置需要加这个

修改application.yml 文件  添加contract

feign:
  client:
    config:
      order-server:
        loggerLevel: FULL
        contract: feign.Contract.Default  #指定Feign原生注解契约配置

通过拦截器实现认证

通常我们调用的接口都是有权限控制的,很多时候可能认证的值是通过参数去传递的,还有就是通过请求头去传递认证信息,比如 Basic 认证方式。

添加bean 实例

@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
    return new BasicAuthRequestInterceptor("jiuge","123456");
}

扩展点  feign.RequestInterceptor

每次 feign 发起http调用之前,会去执行拦截器中的逻辑。

public interface RequestInterceptor {
    /**
     * Called for every request. Add data using methods on the supplied {@link}.
     */
    void apply(RequestTemplate template);
}

使用场景

统一添加 header 信息;

对 body 中的信息做修改或替换;


自定义拦截实现逻辑

public class FeignAuthRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // 业务逻辑
        String access_token = UUID.randomUUID().toString();
        template.header("Authorization",access_token);
    }
}

order-server 端可以通过 @RequestHeader获取请求参数


全局配置

@Configuration  // 全局配置
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
    /**
     * 自定义拦截器
     * @return
     */
    @Bean
    public FeignAuthRequestInterceptor feignAuthRequestInterceptor(){
        return new FeignAuthRequestInterceptor();
    }
}

局部配置

feign:
  client:
    config:
      order-server:
        loggerLevel: FULL
        requestInterceptors[0]:
          com.jiuge.user.interceptor.FeignAuthRequestInterceptor

超时时间配置

通过 Options 可以配置连接超时时间和读取超时时间,Options 的第一个参数是连接的超时时间(ms),默认值是 2s;第二个是请求处理的超时时间(ms),默认值是 5s。

@Bean
public Request.Options options() {
    return new Request.Options(5000, 10000);
}

局部配置

feign:
  client:
    config:
      order-server:
        loggerLevel: FULL
        # 连接超时时间,默认2s
        connectTimeout: 2000
        # 请求处理超时时间,默认5s
        readTimeout: 3000

补充说明:Feign的底层用的是Ribbon,但超时时间以Feign配置为准


客户端组件配置

配置Apache HttpClient

引入依赖

<!-- Apache HttpClient -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.7</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>10.1.0</version>
</dependency>

修改yml 文件 ,启用 apache httpclient

feign:
  #feign 使用 Apache HttpClient  可以忽略,默认开启
  httpclient:
    enabled: true

测试,验证  会进入ApacheHttpClient 中的execute 方法


配置OkHttp

引入依赖

<!-- 引入OkHttp -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

修改yml,将Feign的HttpClient 禁用, 启用OkHttp

feign:
  #feign 使用 okhttp
  okhttp:
    enabled: true

测试,验证   会进入OkHttpClient 类的 execute 方法

GZIP 接口压缩配置

开启压缩可以有效节约网络资源,提升接口性能,可以配置GZIP 来压缩数据

修改yml 文件,为如下内容

feign:
  httpclient:
    enabled: true
  compression:
    request:
      enabled: true
      # 配置压缩的类型
      mime-types: text/xml,application/xml,application/json
      #最小压缩值
      min-request-size: 2048
    response:
      enabled: true

注意:只有当Feign 的Http client 不是okhttp3的时候,压缩才会生效, 配置源码在 FeignAcceptGzipEncodingAutoConfiguration 上

测试,验证

编码器解码器配置

引入jackson 依赖

<!-- 引入jackson 依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-jackson</artifactId>
</dependency>

java 配置方式

@Bean
public Decoder decoder() {
    return new JacksonDecoder();
}
@Bean
public Encoder encoder() {
    return new JacksonEncoder();
}

yml 配置方式

feign:
  client:
    config:
      order-server:  #对应微服务
        # 配置编解码器
        encoder: feign.jackson.JacksonEncoder
        decoder: feign.jackson.JacksonDecoder

以上两种,任选一种进行配置。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
27天前
|
JSON Java 数据格式
【微服务】SpringCloud之Feign远程调用
本文介绍了使用Feign作为HTTP客户端替代RestTemplate进行远程调用的优势及具体使用方法。Feign通过声明式接口简化了HTTP请求的发送,提高了代码的可读性和维护性。文章详细描述了Feign的搭建步骤,包括引入依赖、添加注解、编写FeignClient接口和调用代码,并提供了自定义配置的示例,如修改日志级别等。
71 1
|
2月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
6月前
|
应用服务中间件 nginx 微服务
SpringCloud解决feign调用token丢失问题
【5月更文挑战第2天】在feign调用中可能会遇到如下问题: * 同步调用中,token丢失,这种可以通过创建一个拦截器,将token做透传来解决 * 异步调用中,token丢失,这种就无法直接透传了,因为子线程并没有**token**,这种需要先将token从父线程传递到子线程,再进行透传
429 3
|
2月前
|
前端开发 API 微服务
SpringCloud微服务之间使用Feign调用不通情况举例
SpringCloud微服务之间使用Feign调用不通情况举例
485 2
|
1月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
37 0
|
2月前
|
Java API 开发者
【已解决】Spring Cloud Feign 上传文件,提示:the request was rejected because no multipart boundary was found的问题
【已解决】Spring Cloud Feign 上传文件,提示:the request was rejected because no multipart boundary was found的问题
388 0
|
3月前
|
Java Spring
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
|
3月前
|
Java Spring 容器
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
|
3月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
|
3月前
|
SQL Java 数据库连接
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI