OpenFeign 中 hm-api、消费者、提供者、LoadBalancer、OkHttp 配置总结
最近学习 Spring Cloud OpenFeign,发现最容易混的不是代码本身,而是这些问题:
hm-api、服务消费者、服务提供者分别要加什么依赖?@FeignClient、@EnableFeignClients分别加在哪里?- 多个 Client 时启动类怎么写?
LoadBalancer是写在hm-api还是消费者?OkHttp连接池怎么配置?- Feign 日志怎么开启?
Client方法名和Controller方法名必须一样吗?- MyBatis-Plus 自带的
updateById能不能直接写进 Client?
这里按微服务项目中的常见结构整理一下。
一、三个模块分别负责什么
假设项目结构是:
hm-api
└── com.hmall.api.client
├── ItemClient
├── CartClient
└── OrderClient
item-service
cart-service
trade-service
pay-service
可以这样理解:
hm-api:公共调用契约模块,放 FeignClient 接口和 DTO
服务消费者:真正发起远程调用的服务,比如 trade-service 调 cart-service
服务提供者:被调用的服务,比如 cart-service 提供购物车接口
OpenFeign 的核心规则是:
谁调用别人,谁运行时就必须有 OpenFeign、LoadBalancer;如果启用 OkHttp,谁调用别人,谁也要有 OkHttp。
二、hm-api 公共模块怎么配
hm-api 主要放 FeignClient 接口和 DTO。
一般可以在 hm-api 中放这些依赖:
<!-- 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>
<!-- OkHttp 连接池支持 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
这样消费者只要引入 hm-api,就可以通过 Maven 依赖传递拿到这些依赖。
但是要注意:
依赖可以放在 hm-api 中传递给消费者,但配置开关仍然要写在真正发起调用的消费者服务里。
三、FeignClient 怎么写
比如订单服务要调用购物车服务,删除购物车中的商品。
可以在 hm-api 中定义:
@FeignClient("cart-service")
public interface CartClient {
@DeleteMapping("/carts")
void removeByItemIds(@RequestParam("ids") Collection<Long> ids);
}
这里真正重要的是:
服务名:cart-service
请求方式:DELETE
请求路径:/carts
参数名:ids
@FeignClient("cart-service") 中的 cart-service 要和服务提供者的服务名一致:
spring:
application:
name: cart-service
四、Client 方法名和服务端方法名必须一样吗
不必须。
比如服务提供者中的方法叫:
deleteCartItemByIds
但是 CartClient 中可以写成:
removeByItemIds
这是可以的。
因为 OpenFeign 看的是 HTTP 信息,不是 Java 方法名。
也就是说,只要下面这些对得上就行:
请求方式
请求路径
参数名
服务名
方法名可以按照调用方自己的业务语义来写。
五、服务消费者怎么配
服务消费者是真正发起远程调用的服务,比如:
trade-service 调 item-service
trade-service 调 cart-service
pay-service 调 trade-service
消费者需要引入 hm-api:
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-api</artifactId>
<version>1.0.0</version>
</dependency>
还需要注册中心依赖,比如 Nacos:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
如果 hm-api 没有传递 OkHttp,也可以在消费者中直接引入:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
消费者启动类上要加:
@EnableFeignClients(basePackages = "com.hmall.api.client")
@SpringBootApplication
public class TradeApplication {
public static void main(String[] args) {
SpringApplication.run(TradeApplication.class, args);
}
}
@EnableFeignClients 是加在消费者启动类上的。
也就是:
哪个服务要调用别人,就在哪个服务的启动类上加
@EnableFeignClients。
六、多个 Client 时怎么写
如果一个服务同时用了两个 Client:
private final ItemClient itemClient;
private final CartClient cartClient;
启动类不需要写两个 @EnableFeignClients。
推荐写法是扫描整个 Client 包:
@EnableFeignClients(basePackages = "com.hmall.api.client")
@SpringBootApplication
public class TradeApplication {
}
只要 ItemClient、CartClient、OrderClient 都在:
com.hmall.api.client
这个包下,就都能被扫描到。
也可以指定具体 Client:
@EnableFeignClients(clients = {ItemClient.class, CartClient.class})
@SpringBootApplication
public class TradeApplication {
}
但是以后每增加一个 Client 都要改启动类,所以更推荐 basePackages。
七、为什么有时必须写 basePackages
如果启动类在:
com.hmall.trade
而 FeignClient 在:
com.hmall.api.client
它们不是父子包关系,默认扫描可能扫不到。
所以最好明确写:
@EnableFeignClients(basePackages = "com.hmall.api.client")
这样最稳。
八、服务提供者怎么配
服务提供者主要负责:
注册到 Nacos
提供 HTTP 接口
实现自己的业务逻辑
提供者至少需要:
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos 服务注册发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
提供者如果只是被别人调用,不调用别人,一般不需要:
OpenFeign
LoadBalancer
OkHttp
但是如果提供者自己也要调用别的服务,那它在那个调用关系中也变成了消费者,就也要加这些配置。
九、LoadBalancer 到底写在哪里
LoadBalancer 真正生效的位置是消费者运行时。
但是依赖可以有两种写法。
第一种:写在 hm-api 中,让消费者通过依赖传递拿到。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
第二种:直接写在消费者中。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
两种都可以。
关键不是依赖写在哪个 pom.xml,而是:
消费者服务启动时,classpath 中必须有 LoadBalancer。
服务提供者如果只是被调用,不需要单独配置 LoadBalancer。
十、OkHttp 连接池怎么配
OpenFeign 只是封装 HTTP 调用,底层真正发请求还要依赖 HTTP 客户端。
常见有三种:
HttpURLConnection:默认实现,不支持连接池
Apache HttpClient:支持连接池
OkHttp:支持连接池
如果使用 OkHttp,需要先引入依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
然后在消费者服务中开启:
feign:
okhttp:
enabled: true
注意:这个配置写在消费者服务中。
因为 OkHttp 是消费者发起 HTTP 请求时用的。
如果使用的是较新的 Spring Cloud OpenFeign 版本,配置可能是:
spring:
cloud:
openfeign:
okhttp:
enabled: true
具体看项目版本。
我当前学习项目是 Spring Boot 2.7.x、Spring Cloud 2021.x,所以使用:
feign:
okhttp:
enabled: true
十一、要不要自定义 OkHttp 连接池参数
刚开始学习一般不需要。
默认配置够用,先能跑通调用关系更重要。
如果后期并发请求比较多,可以再自定义:
@Configuration
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
.connectionPool(new ConnectionPool(200, 5, TimeUnit.MINUTES))
.connectTimeout(2, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.build();
}
}
这段配置的意思是:
最多保留 200 个空闲连接
空闲连接最多保留 5 分钟
连接超时时间 2 秒
读取超时时间 5 秒
写入超时时间 5 秒
学习阶段可以先不配。
十二、MP 的 updateById 能不能直接写进 Client
不能。
比如在某个服务内部可以这样写:
orderService.updateById(order);
这是 MyBatis-Plus 的 Service 方法,是 Java 内部方法,不是 HTTP 接口。
OpenFeign 调用的是 HTTP 接口,不会直接调用对方 Service 层的 updateById。
如果别的服务想修改订单状态,正确流程是:
pay-service
-> OrderClient
-> trade-service 暴露的 HTTP 接口
-> orderService.updateById(order)
-> 数据库
所以 Client 里不能凭空写:
void updateById(Order order);
除非服务提供者真的暴露了对应的 HTTP 接口。
更推荐写成业务语义明确的方法:
@FeignClient("trade-service")
public interface OrderClient {
@PutMapping("/orders/{id}/status")
void updateOrderStatus(
@PathVariable("id") Long id,
@RequestParam("status") Integer status
);
}
记住:
Client 里写的是远程 HTTP 接口,不是对方 Service 的 Java 方法。
十三、Feign 日志怎么开启
OpenFeign 调接口时,如果想看到请求地址、请求参数、响应结果,可以开启 Feign 日志。
Feign 日志一般要配两部分:
1. 配置 Feign 的日志级别
2. 配置 Spring Boot 的日志输出级别
第一步,在 hm-api 中写一个公共配置类:
package com.hmall.api.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
public class DefaultFeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
Logger.Level 常见有 4 种:
NONE:不记录日志,默认值
BASIC:只记录请求方法、URL、响应状态码、执行时间
HEADERS:在 BASIC 基础上,额外记录请求头和响应头
FULL:记录请求和响应的 header、body、metadata,最详细
学习和排查问题时可以用:
Logger.Level.FULL
第二步,在消费者启动类上引用这个配置:
@EnableFeignClients(
basePackages = "com.hmall.api.client",
defaultConfiguration = DefaultFeignConfig.class
)
@SpringBootApplication
public class TradeApplication {
}
如果只想给某一个 Client 单独配置,也可以写在 @FeignClient 上:
@FeignClient(value = "cart-service", configuration = DefaultFeignConfig.class)
public interface CartClient {
}
第三步,在消费者服务的 application.yml 中配置日志级别:
logging:
level:
com.hmall.api.client: debug
如果你直接写:
logging:
level:
com.hmall: debug
也可以,因为 com.hmall.api.client 属于 com.hmall 下面。
注意:
只写 Logger.Level.FULL,不一定能看到日志;
还要把对应包的 logging.level 设置成 debug。
开发阶段可以开 FULL,方便排查问题。生产环境一般不要长期使用 FULL,因为日志量比较大,还可能打印请求体、响应体等敏感信息。
十四、完整总结表
| 模块 | 依赖 | 注解或配置 |
|---|---|---|
hm-api |
spring-cloud-starter-openfeign、spring-cloud-starter-loadbalancer、feign-okhttp |
Feign 接口上加 @FeignClient |
| 消费者 | 引入 hm-api、Nacos;运行时要有 LoadBalancer 和 OkHttp |
启动类加 @EnableFeignClients(basePackages = "com.hmall.api.client"),配置 feign.okhttp.enabled=true,需要日志时配置 defaultConfiguration 和 logging.level |
| 提供者 | Web、Nacos | 配置 spring.application.name,提供 HTTP 接口 |
十五、最后总结
这次学习可以按下面几句话记:
hm-api:
定义远程调用契约,放 FeignClient、DTO、Feign 公共配置。
消费者:
真正发起远程调用。
引入 hm-api 和 Nacos。
启动类加 @EnableFeignClients。
运行时要有 OpenFeign、LoadBalancer。
如果使用 OkHttp,要有 feign-okhttp,并配置 feign.okhttp.enabled=true。
提供者:
注册到 Nacos。
暴露 HTTP 接口。
如果只是被调用,不调用别人,一般不需要 OpenFeign、LoadBalancer、OkHttp。
LoadBalancer:
根据服务名选择服务实例,生效在消费者运行时。
OkHttp:
作为 Feign 底层 HTTP 客户端,支持连接池,也生效在消费者运行时。
Feign 日志:
Logger.Level 决定日志详细程度。
logging.level 决定日志是否真正输出。
Client 方法名:
不要求和服务端 Controller 方法名一致。
真正要一致的是服务名、请求方式、请求路径、参数名。
MyBatis-Plus 方法:
updateById 这类方法是服务内部方法,不能直接写进 Client。
想远程调用,必须先由服务提供者暴露 HTTP 接口。
最核心的一句话:
hm-api定义调用契约,消费者开启 Feign 并发起调用,提供者暴露接口;LoadBalancer 和 OkHttp 都是在消费者发起远程调用时生效。
更多推荐




所有评论(0)