Cpte-Boot/cpte-wms-service/FEIGN_USAGE.md

335 lines
9.2 KiB
Markdown
Raw Normal View History

2026-03-06 15:19:25 +08:00
# WMS 微服务 Feign 使用指南
## 一、OpenFeign 简介
OpenFeign 是一个声明式的 Web Service 客户端,它让微服务之间的调用变得更简单。
使用 Feign 只需要创建接口并在接口上添加注解即可,无需手动构建 HTTP 请求。
## 二、项目中的 Feign 配置
### 2.1 依赖配置
已在所有微服务的 `pom.xml` 中添加以下依赖:
```xml
<!-- OpenFeign 服务间调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>4.1.3</version>
</dependency>
<!-- OkHttp 作为 Feign 的 HTTP 客户端 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>13.5</version>
</dependency>
```
### 2.2 Feign Client 配置
**配置类**: `org.cpte.feign.config.FeignClientConfiguration`
主要配置项:
- **HTTP 客户端**: 使用 OkHttp
- **连接超时**: 5 秒
- **读取超时**: 10 秒
- **日志级别**: BASIC可调整为 FULL 查看完整日志)
- **重试机制**: 最多重试 3 次
### 2.3 Fallback 降级处理
为每个 Feign Client 都配置了 FallbackFactory当服务调用失败时会执行降级逻辑
- `BasicServiceFallbackFactory` - 基础服务降级
- `InventoryServiceFallbackFactory` - 库存服务降级
- `ScheduleServiceFallbackFactory` - 调度服务降级
## 三、已有的 Feign Client
### 3.1 基础服务 Client
**接口**: `org.cpte.feign.client.BasicServiceClient`
**功能**:
- 获取物品信息(按 ID/编码)
- 获取区域信息(按 ID/编码)
- 获取点位信息(按 ID/编码)
- 批量查询物品/点位列表
**使用示例**:
```java
@Autowired
private BasicServiceClient basicServiceClient;
// 获取物品信息
Result<Map<String, Object>> result = basicServiceClient.getItemById("item123");
// 批量获取点位
List<String> pointCodes = Arrays.asList("P001", "P002", "P003");
Result<List<Map<String, Object>>> points = basicServiceClient.getPointByCodes(pointCodes);
```
### 3.2 库存服务 Client
**接口**: `org.cpte.feign.client.InventoryServiceClient`
**功能**:
- 查询库存(单个/批量)
- 增加库存
- 扣减库存
- 预占库存
- 释放预占库存
- 查询库存流水
**使用示例**:
```java
@Autowired
private InventoryServiceClient inventoryServiceClient;
// 查询库存
Result<Map<String, Object>> stock = inventoryServiceClient.queryInventory("item123", "point456");
// 增加库存
Map<String, Object> params = new HashMap<>();
params.put("itemId", "item123");
params.put("quantity", 100);
Result<Boolean> result = inventoryServiceClient.increaseInventory(params);
```
### 3.3 调度服务 Client
**接口**: `org.cpte.feign.client.ScheduleServiceClient`
**功能**:
- 创建 AGV 上架任务
- 创建 AGV 下架任务
- 创建 AGV 搬运任务
- 查询任务状态
- 取消任务
- 等待任务完成
**使用示例**:
```java
@Autowired
private ScheduleServiceClient scheduleServiceClient;
// 创建上架任务
Map<String, Object> params = new HashMap<>();
params.put("fromPoint", "RECEIVE_AREA");
params.put("toPoint", "POINT001");
params.put("taskId", "TASK_001");
Result<String> result = scheduleServiceClient.createPutTask(params);
// 等待任务完成
Result<Map<String, Object>> taskResult = scheduleServiceClient.waitTaskComplete("TASK_001", 300000L);
```
## 四、完整业务流程示例
### 4.1 入库流程
```java
@Service
public class InboundService {
@Autowired
private BasicServiceClient basicServiceClient;
@Autowired
private InventoryServiceClient inventoryServiceClient;
@Autowired
private ScheduleServiceClient scheduleServiceClient;
@Transactional(rollbackFor = Exception.class)
public Result<String> inbound(String itemId, String pointId, Integer quantity) {
// 1. 验证物品和库位
Result<Map<String, Object>> itemResult = basicServiceClient.getItemById(itemId);
if (!itemResult.isSuccess()) {
return Result.error("物品不存在");
}
Result<Map<String, Object>> pointResult = basicServiceClient.getPointById(pointId);
if (!pointResult.isSuccess()) {
return Result.error("库位不存在");
}
// 2. 增加库存
Map<String, Object> params = new HashMap<>();
params.put("itemId", itemId);
params.put("pointId", pointId);
params.put("quantity", quantity);
Result<Boolean> increaseResult = inventoryServiceClient.increaseInventory(params);
if (!increaseResult.isSuccess()) {
return Result.error("增加库存失败");
}
// 3. 创建 AGV 上架任务
Map<String, Object> taskParams = new HashMap<>();
taskParams.put("fromPoint", "RECEIVE_AREA");
taskParams.put("toPoint", pointId);
taskParams.put("taskId", "PUT_" + System.currentTimeMillis());
taskParams.put("taskType", "PUT");
Result<String> taskResult = scheduleServiceClient.createPutTask(taskParams);
return Result.OK("入库成功", taskResult.getResult());
}
}
```
### 4.2 出库流程
```java
@Service
public class OutboundService {
@Autowired
private InventoryServiceClient inventoryServiceClient;
@Autowired
private ScheduleServiceClient scheduleServiceClient;
@Transactional(rollbackFor = Exception.class)
public Result<String> outbound(String itemId, String pointId, Integer quantity, String orderNo) {
// 1. 预占库存
Map<String, Object> reserveParams = new HashMap<>();
reserveParams.put("itemId", itemId);
reserveParams.put("pointId", pointId);
reserveParams.put("quantity", quantity);
reserveParams.put("orderNo", orderNo);
Result<Boolean> reserveResult = inventoryServiceClient.reserveInventory(reserveParams);
if (!reserveResult.isSuccess()) {
return Result.error("预占库存失败");
}
// 2. 创建 AGV 下架任务
Map<String, Object> taskParams = new HashMap<>();
taskParams.put("fromPoint", pointId);
taskParams.put("toPoint", "SHIPMENT_AREA");
taskParams.put("taskId", "REMOVE_" + orderNo);
taskParams.put("taskType", "REMOVE");
Result<String> taskResult = scheduleServiceClient.createRemoveTask(taskParams);
return Result.OK("出库成功", taskResult.getResult());
}
}
```
## 五、配置说明
### 5.1 application.yml 配置
```yaml
# Feign 配置
feign:
client:
config:
default:
connectTimeout: 5000 # 连接超时 5 秒
readTimeout: 10000 # 读取超时 10 秒
loggerLevel: BASIC # 日志级别
okhttp:
enabled: true # 启用 OkHttp
compression:
request:
enabled: true # 启用请求压缩
response:
enabled: true # 启用响应压缩
# 服务地址配置K8s 环境使用服务名)
feign:
client:
wms-basic:
url: http://wms-basic-service:80
wms-inventory:
url: http://wms-inventory-service:80
wms-schedule:
url: http://wms-schedule-service:80
```
### 5.2 日志级别调整
开发环境可调整为 FULL 查看详细请求响应:
```yaml
logging:
level:
org.cpte.feign.client: DEBUG
feign:
client:
config:
default:
loggerLevel: FULL
```
## 六、注意事项
### 6.1 服务调用超时
- 默认连接超时 5 秒,读取超时 10 秒
- 对于耗时操作(如等待 AGV 任务),使用异步方式或增加超时时间
- 建议设置合理的超时时间,避免线程阻塞
### 6.2 服务降级
- 所有 Feign Client 都配置了 FallbackFactory
- 降级处理会返回友好的错误信息
- 生产环境建议实现更完善的降级策略(如返回缓存数据)
### 6.3 事务处理
- 跨服务调用时,本地事务无法保证分布式一致性
- 建议使用最终一致性方案(如消息队列、补偿机制)
- 关键业务操作需要实现幂等性
### 6.4 性能优化
- 启用 HTTP 压缩减少网络传输
- 使用连接池提高连接复用率
- 批量查询代替循环调用
- 合理使用缓存减少服务调用
## 七、调试技巧
### 7.1 查看 Feign 日志
```yaml
logging:
level:
org.cpte.feign.client: DEBUG
feign: DEBUG
```
### 7.2 监控服务调用
- 使用 Actuator 端点监控 HTTP 请求
- 集成 Prometheus + Grafana 监控服务调用指标
- 使用 SkyWalking 进行链路追踪
### 7.3 本地测试
本地开发时,可以通过 Host 映射或配置中心指定服务地址:
```yaml
# 本地开发环境
feign:
client:
wms-basic:
url: http://localhost:8001
wms-inventory:
url: http://localhost:8004
wms-schedule:
url: http://localhost:8005
```
## 八、最佳实践
1. **统一响应格式**: 所有服务接口返回统一的 Result 对象
2. **参数校验**: 在调用前校验参数,减少无效调用
3. **批量操作**: 优先使用批量接口,减少调用次数
4. **超时控制**: 根据业务场景设置合理的超时时间
5. **降级策略**: 实现完善的降级逻辑,提高系统可用性
6. **幂等性**: 关键操作实现幂等性,支持重试
7. **链路追踪**: 集成 SkyWalking 等工具,便于问题排查