Spring Cloud OpenFeign 中 hm-api、消费者、提供者、LoadBalancer、OkHttp 应该怎么配置
Spring Cloud OpenFeign 中 hm-api、消费者、提供者、LoadBalancer、OkHttp 应该怎么配置
最近学习 Spring Cloud OpenFeign 的时候,我发现有几个点特别容易混:
hm-api公共模块到底放什么?- 服务消费者和服务提供者分别要加什么依赖?
@EnableFeignClients、@FeignClient、@RestController分别加在哪里?spring-cloud-starter-loadbalancer写在hm-api还是消费者?- OkHttp 连接池要在哪个服务里开启?
Controller方法名和FeignClient方法名不一样能不能调用?
这篇文章按一个真实调用关系整理一下。
一、项目结构
项目大概是这样的:
hm-api
└── com.hmall.api.client
├── ItemClient
└── CartClient
cart-service
└── CartController
trade-service
└── OrderServiceImpl
其中:
hm-api:公共 API 模块,放 FeignClient 接口和 DTO;cart-service:服务提供者,提供购物车接口;trade-service:服务消费者,下单时调用购物车服务;- 注册中心:Nacos;
- 远程调用:OpenFeign;
- 负载均衡:Spring Cloud LoadBalancer;
- HTTP 连接池:OkHttp。
二、一句话结论
可以先记住这句话:
谁发起远程调用,谁运行时就必须有 OpenFeign、LoadBalancer,如果要使用连接池,还要有 OkHttp 并开启配置。
所以:
hm-api负责定义调用接口;- 消费者负责真正发起调用;
- 提供者负责暴露 Controller 接口;
- LoadBalancer 和 OkHttp 真正生效的位置都是消费者运行时。
三、hm-api 公共模块怎么配置
hm-api 一般放:
- FeignClient 接口;
- DTO;
- Feign 相关公共配置。
hm-api/pom.xml 可以这样写:
<!-- 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 中,消费者只要引入 hm-api,就可以通过 Maven 依赖传递拿到 OpenFeign、LoadBalancer、OkHttp。
但是注意:
依赖可以从
hm-api传递过去,配置仍然要在消费者服务中开启。
比如 OkHttp 的开关要写在真正发起调用的服务里。
四、FeignClient 怎么写
比如 trade-service 要调用 cart-service 删除购物车中的商品,可以在 hm-api 中定义:
@FeignClient("cart-service")
public interface CartClient {
@DeleteMapping("/carts")
void removeByItemIds(@RequestParam("ids") Collection<Long> ids);
}
这里要注意四个对应关系:
服务名:cart-service
请求方式:DELETE
请求路径:/carts
请求参数:ids
这些必须和服务提供者的 Controller 对上。
五、Controller 方法名和 Client 方法名必须一样吗
不需要一样。
比如 cart-service 中的 Controller 是:
@RestController
@RequestMapping("/carts")
public class CartController {
@DeleteMapping
public void deleteCartItemByIds(@RequestParam("ids") List<Long> ids) {
cartService.removeByItemIds(ids);
}
}
这里 Controller 方法名叫:
deleteCartItemByIds
而 FeignClient 方法名叫:
removeByItemIds
这完全可以。
因为 OpenFeign 调用时看的不是 Java 方法名,而是 HTTP 接口信息:
DELETE /carts?ids=1&ids=2&ids=3
所以只要请求方式、路径、参数名对得上,方法名可以按各自业务语义来命名。
六、服务提供者 cart-service 怎么配置
服务提供者的职责是:
- 注册到 Nacos;
- 暴露 Controller 接口;
- 提供业务实现。
cart-service/pom.xml 至少需要:
<!-- 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>
如果 cart-service 只是被别人调用,不主动调用别的服务,那么它本身不一定需要 OpenFeign、LoadBalancer、OkHttp。
但是如果 cart-service 自己也要调用 item-service、user-service 等其他服务,那它在那个调用关系中也变成了消费者,就也需要配置 OpenFeign。
application.yml 示例:
spring:
application:
name: cart-service
cloud:
nacos:
server-addr: 192.168.18.99:8848
Controller 示例:
@RestController
@RequestMapping("/carts")
public class CartController {
@DeleteMapping
public void deleteCartItemByIds(@RequestParam("ids") List<Long> ids) {
cartService.removeByItemIds(ids);
}
}
七、服务消费者 trade-service 怎么配置
服务消费者的职责是:
- 引入
hm-api; - 注册到 Nacos;
- 开启 FeignClient 扫描;
- 如果使用 OkHttp,开启 OkHttp 配置。
trade-service/pom.xml:
<!-- 引入公共 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);
}
}
为什么建议写 basePackages?
因为 TradeApplication 在:
com.hmall.trade
而 FeignClient 在:
com.hmall.api.client
它们不是父子包关系。如果只写:
@EnableFeignClients
可能扫描不到 hm-api 中的 FeignClient。
所以最好明确指定:
@EnableFeignClients(basePackages = "com.hmall.api.client")
消费者的 application.yml:
spring:
application:
name: trade-service
cloud:
nacos:
server-addr: 192.168.18.99:8848
feign:
okhttp:
enabled: true
我的项目使用的是 Spring Boot 2.7.12、Spring Cloud 2021.0.3,所以 OkHttp 开关写:
feign:
okhttp:
enabled: true
如果是较新的 Spring Cloud OpenFeign 版本,可能要写成:
spring:
cloud:
openfeign:
okhttp:
enabled: true
具体以项目版本为准。
八、调用代码怎么写
消费者中直接注入 CartClient:
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements IOrderService {
private final CartClient cartClient;
public void createOrder(List<Long> itemIds) {
cartClient.removeByItemIds(itemIds);
}
}
这时调用过程大概是:
trade-service
-> CartClient.removeByItemIds(itemIds)
-> DELETE http://cart-service/carts?ids=...
-> Nacos 找到 cart-service 实例
-> LoadBalancer 选择一个实例
-> OkHttp 发送 HTTP 请求
-> CartController.deleteCartItemByIds(...)
-> cartService.removeByItemIds(...)
九、LoadBalancer 到底写在哪里
LoadBalancer 真正生效的位置是消费者运行时。
但是依赖可以有两种写法。
第一种,写在 hm-api 中:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
消费者引入 hm-api 后,通过依赖传递拿到 LoadBalancer。
第二种,直接写在消费者中:
<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:支持连接池
如果使用默认的 HttpURLConnection,每次请求的性能不如连接池方案。
集成 OkHttp 后,Feign 底层会使用 OkHttp 发请求,OkHttp 会复用 HTTP 连接,减少频繁创建连接的开销。
最基本的配置就是两步:
第一步,引入依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
第二步,在消费者中开启:
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 秒
不过刚开始学习时,先用默认连接池配置即可,没必要一上来就调这些参数。
十二、完整配置总结
最后可以用这张表总结:
| 模块 | 依赖 | 注解或配置 |
|---|---|---|
hm-api |
spring-cloud-starter-openfeign、spring-cloud-starter-loadbalancer、feign-okhttp |
Feign 接口加 @FeignClient |
消费者,比如 trade-service |
引入 hm-api、Nacos;如果 hm-api 没传递 OkHttp,就自己引入 feign-okhttp |
启动类加 @EnableFeignClients(basePackages = "com.hmall.api.client"),配置 feign.okhttp.enabled=true |
提供者,比如 cart-service |
Web、Nacos | Controller 加 @RestController、@RequestMapping,配置 spring.application.name=cart-service |
十三、最终记忆方式
我现在会这样记:
hm-api:定义调用契约,放 FeignClient 和 DTO。
消费者:真正发起远程调用,负责开启 @EnableFeignClients,运行时要有 OpenFeign、LoadBalancer、OkHttp。
提供者:注册到 Nacos,暴露 Controller 接口。
LoadBalancer:负责根据服务名选择实例,生效在消费者运行时。
OkHttp:负责底层 HTTP 请求和连接池,也生效在消费者运行时。
最重要的一句话:
FeignClient 方法名不要求和 Controller 方法名一致;真正要一致的是服务名、请求方式、请求路径和参数名。
更多推荐




所有评论(0)