云计算百科
云计算领域专业知识百科平台

OpenFeign 详解:调用机制、连接池、公共模块与日志配置完整指南(基于黑马商城项目实现)(springcloud微服务课day5)

OpenFeign 详解:调用机制、连接池、公共模块与日志配置完整指南(基于黑马商城项目)

前置条件,nacos的实现:nacos的部署详解

📚 目录(点击跳转对应章节)

一、OpenFeign 的核心思想 二、快速接入 OpenFeign(完整流程) 三、OpenFeign 底层调用执行流程 四、Feign 连接池配置(性能关键) 五、Feign 客户端抽取为公共模块 六、Feign 扫描不到接口的问题 七、Feign 日志配置(排障必备) 八、总结:什么时候必须用 Feign


在微服务架构中,服务之间通过 HTTP 进行远程调用是最基础的能力之一。

如果直接使用 RestTemplate 进行调用,通常需要手动:

  • 拼接 URL
  • 处理参数
  • 解析返回值
  • 编写大量样板代码

远程调用代码和业务逻辑混在一起,可读性和维护性都不理想,而且调用方式与本地方法差异很大。

OpenFeign 的目标很明确:

让远程 HTTP 调用像本地方法调用一样简单。

它通过"接口 + 注解 + 动态代理"的方式,把远程调用彻底声明化。


一、OpenFeign 的核心思想

一次 HTTP 远程调用,本质只包含四个要素:

  • 请求方式(GET/POST/PUT/DELETE)
  • 请求路径
  • 请求参数
  • 返回值类型

OpenFeign 的做法是:

  • 使用 SpringMVC 注解描述请求信息
  • 启动时为接口创建动态代理
  • 调用接口方法时自动发起 HTTP 请求

开发者只需要写接口,不需要写实现类。

示例:

@FeignClient("item-service")
public interface ItemClient {

@GetMapping("/items")
List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}

调用时:

itemClient.queryItemByIds(ids);

形式与本地方法调用完全一致。


二、快速接入 OpenFeign(完整流程)

示例场景:

cart-service 调用 item-service 查询商品信息。


1. 引入依赖

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

<!– 负载均衡 –>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

说明:

  • openfeign:提供声明式 HTTP 客户端
  • loadbalancer:根据服务名选择实例并负载均衡

Feign 负责"怎么发请求",LoadBalancer 负责"选哪个实例"。


2. 启用 Feign 功能

启动类添加:

@EnableFeignClients

作用:

  • 开启 Feign 自动配置
  • 扫描 @FeignClient 接口
  • 为接口生成代理对象并注册为 Bean

不加这个注解,Feign 接口不会生效。


3. 编写 Feign 客户端接口

@FeignClient("item-service")
public interface ItemClient {

@GetMapping("/items")
List<ItemDTO> queryItemByIds(
@RequestParam("ids") Collection<Long> ids
);
}

关键点说明:

@FeignClient
  • 声明远程服务名称
  • 必须与注册中心服务名一致
  • 实际访问时会通过服务发现解析真实地址

@GetMapping
  • 指定请求方式
  • 指定请求路径
  • 必须与服务端 Controller 保持一致

@RequestParam
  • 指定查询参数
  • 参数名必须与服务端一致
  • 集合类型会被编码为多个参数:

/items?ids=1&ids=2&ids=3


返回值类型

Feign 会自动完成:

JSON → Java对象

通过 Decoder 使用 Spring 消息转换器完成反序列化。


4. 在业务代码中使用

@Autowired
private ItemClient itemClient;

List<ItemDTO> items = itemClient.queryItemByIds(ids);

Feign 自动完成:

  • 服务发现
  • 实例选择
  • 负载均衡
  • HTTP 请求构建
  • 参数编码
  • JSON 转换

无需再使用 RestTemplate。


三、OpenFeign 底层调用执行流程

在此不详细说明,而是只展示底层调用流程,相关代码可以自行查看源码

Feign 的执行链路非常清晰:


调用链路

接口方法调用
→ JDK动态代理(InvocationHandler)
→ SynchronousMethodHandler(InvocationHandler 的实现)
→ 解析方法元数据(FeignClient 接口的方法信息)
→ 构建 RequestTemplate(根据方法元数据填充请求信息)
→ LoadBalancer 选择实例(根据服务名获取实例列表,再根据负载均衡策略选择一个实例)
→ Client 发送 HTTP 请求(根据 RequestTemplate 构建 HTTP 请求)
→ Decoder 解析响应(根据响应体和返回值类型,使用 Spring 消息转换器完成反序列化)
→ 返回 Java 对象(根据返回值类型,使用 Spring 消息转换器完成序列化)


核心组件说明

SynchronousMethodHandler

负责拦截接口方法调用,并驱动整个请求流程。


RequestTemplate

封装:

  • 请求方法
  • URL
  • 参数
  • Header
  • Body

FeignBlockingLoadBalancerClient

负责:

  • 根据服务名获取实例列表
  • 负载均衡选择一个实例

四、Feign 连接池配置(性能关键)

Feign 本身不提供连接池,它依赖底层 HTTP 客户端。


默认客户端问题

默认实现:

HttpURLConnection

特点:

  • 无连接池
  • 每次新建连接
  • 高并发性能差

生产环境不推荐使用。


可选客户端

支持连接池的实现:

  • Apache HttpClient
  • OKHttp

实际项目中 OKHttp 使用更广泛。


使用 OKHttp

引入依赖

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>


开启配置

feign:
okhttp:
enabled: true


五、Feign 客户端抽取为公共模块

问题场景:

多个服务都需要调用 item-service:

  • cart-service
  • trade-service

如果各写一份 FeignClient,会产生重复代码。


抽取策略选择

两种方案:

方案一:统一公共模块 优点:结构清晰 缺点:服务耦合偏高

方案二:每服务单独模块 优点:解耦更好 缺点:结构复杂

由于黑马商城将模块放在一个hamll包下,所以选择方案一,且下列讲解也是基于方案一。


抽取方案

创建公共模块:

hm-api

包含:

  • FeignClient 接口
  • DTO 对象
  • Feign 配置类

公共模块依赖

openfeign
loadbalancer
swagger-annotations


使用方式

其它服务只需依赖 hm-api:

<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-api</artifactId>
</dependency>

即可直接注入使用。


六、Feign 扫描不到接口的问题

常见错误:

No qualifying bean of type ItemClient

原因:

FeignClient 不在启动类扫描路径内。


解决方式一:指定扫描包

@EnableFeignClients(
basePackages = "com.hmall.api.client"
)


解决方式二:指定接口类

@EnableFeignClients(
clients = ItemClient.class
)


七、Feign 日志配置(排障必备)

Feign 默认日志级别:

NONE

不输出任何请求信息。


四种日志级别

NONE 不输出日志

BASIC 方法 + URL + 状态码 + 耗时

HEADERS 包含请求头和响应头

FULL 包含请求体和响应体


定义日志级别配置

public class DefaultFeignConfig {

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


让配置生效

局部生效

@FeignClient(
value = "item-service",
configuration = DefaultFeignConfig.class
)


全局生效

@EnableFeignClients(
defaultConfiguration = DefaultFeignConfig.class
)


日志开启的前提

必须同时满足:

  • Feign Logger.Level 已配置
  • FeignClient 所在包日志级别为 DEBUG

例如:

logging:
level:
com.hmall.api.client: DEBUG


八、总结:什么时候必须用 Feign

在微服务体系中,只要满足以下条件,就应该优先使用 Feign:

  • 服务间 HTTP 调用频繁
  • 需要负载均衡
  • 希望调用方式统一
  • 需要良好的可读性
  • 需要减少样板代码

一句话总结:

Feign 不是为了 “少写代码”,而是为了让远程调用模型与本地调用模型一致,从而降低系统复杂度。

赞(0)
未经允许不得转载:网硕互联帮助中心 » OpenFeign 详解:调用机制、连接池、公共模块与日志配置完整指南(基于黑马商城项目实现)(springcloud微服务课day5)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!