openfeign
目录
1. 官方文档
2. 如何使用
2.1. 引入依赖
2.1.1. Spring Cloud 2020.0及之前版本
- 默认Netflix Ribbon作为负载均衡器。
2.1.2. Spring Cloud 2022.0.x及之后版本
-
从2022.0.1版本开始,Spring Cloud引入了spring-cloud-loadbalancer组件作为默认的负载均衡解决方案,以取代Netflix Ribbon。
-
同时需要显示引入loadbalancer
<!-- loadbalancer 负载均衡器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!-- openfeign 远程调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2. 启动类添加注解
- 启动类上添加@EnableFeignClients
2.3. 定义接口,添加注解@FeignClient
package org.tuling.tlmalluseropenfeigndemo.feign;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.*;
import org.tuling.tlmallcommon.Result;
import org.tuling.tlmalluseropenfeigndemo.feign.dto.OrderDTO;
//FeignConfig局部配置,让指定的微服务生效,在@FeignClient 注解中指定configuration
//@FeignClient(value = "mall-order",path = "/order",configuration = FeignConfig.class)
// tlmall-order01=服务名
@FeignClient(value = "tlmall-order01",path = "/order")
public interface OrderFeignService {
/**
* 根据用户id查询订单信息
* @param userId
* @return
*/
@GetMapping("/getOrder")
Result<?> getOrder(@RequestParam("userId") String userId);
@GetMapping(value = "/post1")
Result<?> post1(@RequestBody OrderDTO orderDTO);
@PostMapping("/post2")
Result<?> post2(@RequestBody OrderDTO orderDTO,@RequestParam("token") String token);
@PostMapping(value = "/post3/{userId}")
Result<?> post3(@RequestBody OrderDTO orderDTO, @PathVariable("userId") String userId);
}
3. 接口规范
3.1. 总结
和Controller那边的写法很像,可以直接拷贝
- get请求,参数注意要加@RequestParam
3.2. 方法上和springmvc一样,必须添加@RequestMapping注解
- @GetMapping、@PostMapping、@PutMapping等
3.3. 用@HeaderMap传递头部信息
3.4. 参数为对象问题
没法像普通controller请求样,如要直接用对象接受,必须加@RequestBody。
3.5. @RequestParam注解的坑
Feign接口的方法参数名和另一个接口的参数名一致,也要显示注明,不然会报错:.IllegalStateException: RequestParam.value() was empty on parameter 0

3.6. @PathVariable
注解也要显示的表明value的值为参数名,栗子:ResultData
3.7. post请求要用@RequestBody
两边服务的参数名要一致
- post请求,示例
// url请求路径表单传参,body也传参
@PostMapping("/post2")
Result<?> post2(@RequestBody OrderDTO orderDTO,@RequestParam("token") String token);
// url请求路径传参,body也传参
@PostMapping(value = "/post3/{userId}")
Result<?> post3(@RequestBody OrderDTO orderDTO, @PathVariable("userId") String userId);
3.8. 启动类注解
- 消费者模块,启动类使用@EnableFeignClients(basePackages = "com.javadaily.feign.*"),一定要指明Feign接口的包路径,否则会报错

4. 配置项
4.1. http请求配置
默认使用JDK原生的http请求类,性能一般
4.1.1. 配置为Apache HttpClient5
- 1:引入依赖
<!-- Apache HttpClient5 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
</dependency>
- 2:yml文件
注意看FeignAutoConfiguration源码的逻辑
spring.cloud.openfeign.http2client.enabled=true
- 3:FeignAutoConfiguration自动装配类的逻辑
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({ApacheHttp5Client.class})
@ConditionalOnMissingBean({CloseableHttpClient.class})
@ConditionalOnProperty(
value = {"spring.cloud.openfeign.httpclient.hc5.enabled"},
havingValue = "true",
matchIfMissing = true
)
@Import({org.springframework.cloud.openfeign.clientconfig.HttpClient5FeignConfiguration.class})
protected static class HttpClient5FeignConfiguration {
protected HttpClient5FeignConfiguration() {
}
@Bean
@ConditionalOnMissingBean({Client.class})
public Client feignClient(CloseableHttpClient httpClient5) {
return new ApacheHttp5Client(httpClient5);
}
}
4.1.2. 配置为OKHttp
- 1:引入依赖
<!-- okhttp -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
- 2:yml配置
# FeignAutoConfiguration中找
spring.cloud.openfeign.okhttp.enabled=true
4.2. 日志配置
4.2.1. 日志级别
- NONE, No logging (DEFAULT).
- BASIC(生产推荐), Log only the request method and URL and the response status code and execution time.
- HEADERS, Log the basic information along with request and response headers,BASIC信息基础上再加请求头信息.
- FULL, Log the headers, body, and metadata for both requests and responses.
Logger.Level.BASIC

Logger.Level.FULL

4.2.2. JavaBean方式
4.2.2.1. yml文件配置
# 固定debug
logging:
level:
#@FeignClient对应类所在包
包名路径(示例:com.jf.user.feign):debug
4.2.2.2. 全局生效
// 全局生效方式
@Configuration
public class FooConfiguration {
// feign.Logger包
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
4.2.2.3. 局部生效
- @FeignClient注解指定
- BarConfiguration类上不加@Configuration
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
public interface BarClient {
//..
}
4.2.3. yml方式
4.2.3.1. 全局生效
# 对项目所有openFeign的client都生效
spring.cloud.openfeign.client.config.default.loggerLevel: BASIC
4.2.3.2. 局部生效
# 局部生效
spring.cloud.openfeign.client.config.@FeignClient中value的值.loggerLevel: BASIC
4.3. 超时配置
4.3.1. 注意点
- 如果同时配置了openfeign和loadbalancer,超时时间以openfeign的为准。
4.3.2. 参数说明
- connectTimeout (连接超时)
连接超时指的是客户端尝试与服务器建立连接(即TCP连接)的最长时间。如果在这个时间内无法建立连接,则会抛出超时异常
英文原话:prevents blocking the caller due to the long server processing time - readTimeout (读取超时)
读取超时指的是客户端从服务器读取数据的最长时间。从建立连接开始算,如果在这个时间内客户端没有从服务器接收到任何数据,则会抛出超时异常
英文原话: is applied from the time of connection establishment and is triggered when returning the response takes too long.
4.3.3. 优先级
spring:
cloud:
openfeign:
client:
config:
# 局部配置
# store-server == @FeignClient中value的值
store-server:
# 连接超时,拨电话后5秒必须打通,嘟嘟嘟的时间【默认10s】
connectTimeout: 5000
# 获取响应信息超时,电话打通后,我说喂,对方5秒内必须回答【默认60s】
readTimeout: 5000
loggerLevel: basic
# 全局
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
4.4. @RequestLine调用
- 配置文件需要添加
spring:
cloud:
openfeign:
client:
config:
contract: feign.Contract.Default
- 使用示例
@RequestLine("GET /getOrder?userId={id}")
Result<?> getOrder(@Param("userId") String userId);
4.5. 压缩配置
- FeignAcceptGzipEncodingAutoConfiguration
#开关
spring.cloud.openfeign.compression.request.enabled=true
# 压缩数据类型,之支持这3种,代码里数组mimeTypes固定的
spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
# 超过多少才压缩,单位字节
spring.cloud.openfeign.compression.request.min-request-size=2048
4.6. 编码配置
- 支持自定义实现
4.6.1. 引入依赖
<!-- jackson -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<!-- gson -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
</dependency>
4.6.2. 指定
- 配置类中注册bean(不推荐)
@Bean
Public Decoder decoder() {
return new JacksonDecoder();
}
@Bean
Public Encoder encoder() {
return new JacksonEncoder();
}
- yml指定
openfeign:
client:
config:
tlmall-order01:
# 指定编码器
encoder: feign.jackson.JacksonEncoder
# 指定解码器
decoder: feign.jackson.JacksonDecoder
4.7. 拦截器配置
- token统一传递
4.7.1. 实现接口 RequestIntercepor
@Slf4j
public class FeignAuthRequestInterceptor implements RequestInterceptor {
/**
*
* @param template 自己发给别人的请求
*/
@Override
public void apply(RequestTemplate template) {
// 业务逻辑 模拟认证逻辑
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
if(null != attributes){
// 别人发给我的请求
HttpServletRequest request = attributes.getRequest();
String access_token = request.getHeader("Authorization");
log.info("从Request中解析请求头:{}",access_token);
//设置token
template.header("Authorization",access_token);
}
}
}
4.7.2. yml添加
spring:
cloud:
openfeign:
client:
config:
feignName:
requestInterceptors:
- com.example.FeignAuthRequestInterceptor
4.8. 如何动态刷新配置项的值
官方提示,不要在@FeignClient类上加@RefreshScope
spring.cloud.openfeign.client.refresh-enabled=true
- 按官方说法,只有3个东西可以动态刷新,connectTimeout and readTimeout,url
- feign.Request.Options as a refresh-scoped bean. This means properties such as connectTimeout and readTimeout can be refreshed against any Feign client instance.
- A url wrapped under org.springframework.cloud.openfeign.RefreshableUrl. This means the URL of Feign client, if defined with spring.cloud.openfeign.client.config.{feignName}.url property, can be refreshed against any Feign client instance.

浙公网安备 33010602011771号