下载工作台
Spring Cloud 微服务

BFF 聚合与 API 编排

试读上半部分 · 解锁后可读全文

第 8 章 · BFF 聚合与 API 编排

本章目标:理解 BFF(Backend for Frontend) 在微服务架构中的定位;在 svc-spring-demo 新增 bff-svc,聚合订单详情(订单 + 商品 + 用户)为单一响应;掌握 并行 Feign 调用部分失败降级超时预算;对比 BFF 与 API Gateway 聚合GraphQL 的适用场景;为移动端与 Web SPA 提供差异化接口(概念)。

学时建议:5~6 小时(含 2 小时 bff-svc 联调)

前置spring-cloud-web ch01~ch07spring-boot-web ch07 统一响应;OpenFeign 与 Resilience4j 熔断(ch04~ch05)。


8.1 为什么需要 BFF

ch03 gateway-svc 负责路由、鉴权、限流,但不应承载复杂业务聚合逻辑。前端若自行串联多个 API:

SPA 加载「订单详情页」
  GET /api/v1/orders/1001        → order-svc
  GET /api/v1/products/42        → product-svc(从订单项解析)
  GET /api/v1/users/7            → user-svc
问题BFF 方案
多次往返、瀑布请求一次 GET /bff/v1/orders/1001/detail
前端耦合微服务边界聚合逻辑收敛到服务端
移动端/Web 字段差异不同 BFF 面向不同客户端(选修)
错误处理分散BFF 统一降级与错误码
  Web SPA / 移动端
        │
        ▼
┌─────────────────┐     ┌──────────────────┐
│  gateway-svc    │────►│  bff-svc         │
│  api.example.com│     │  聚合编排         │
└────────┬────────┘     └────────┬─────────┘
         │                       │ 并行 Feign
         │              ┌────────┼────────┐
         │              ▼        ▼        ▼
         │         order-svc product-svc user-svc
         └────────► 其他直连路由(非聚合 API)
虚构 bff-svcapi.example.com;BFF 仍注册 Nacos,经 Gateway 暴露 /bff/** 前缀。

8.2 BFF vs Gateway vs GraphQL

模式职责优点缺点
Gateway 路由转发、鉴权、限流无状态、高性能不宜写业务聚合
BFF面向前端的 API 编排减少客户端复杂度多客户端可能多 BFF
GraphQL客户端自选字段灵活查询服务端 N+1、缓存复杂

教学选型:本课程用 Spring MVC + Feign 实现 BFF,与现有技术栈一致;GraphQL 作为了解即可。


8.3 创建 bff-svc 模块

8.3.1 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

8.3.2 启动类

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.example.svc.bff.client")
public class BffSvcApplication {
    public static void main(String[] args) {
        SpringApplication.run(BffSvcApplication.class, args);
    }
}

application.yml

spring:
  application:
    name: bff-svc
server:
  port: 8095

8.4 聚合 DTO 设计

svc-common 新增面向前端的视图对象,避免泄露各服务内部实体:

public record OrderDetailVO(
    Long orderId,
    String status,
    BigDecimal totalAmount,
    Instant createdAt,
    UserBriefVO buyer,
    List<OrderLineDetailVO> lines
) {}

public record OrderLineDetailVO(
    Long productId,
    String productName,
    String coverUrl,
    int quantity,
    BigDecimal unitPrice
) {}

public record UserBriefVO(Long id, String nickname, String avatarUrl) {}
原则说明
只暴露前端需要的字段不含密码哈希、内部状态码
命名面向 UIcoverUrl 而非 productImagePath
版本独立BFF VO 变更不影响领域服务 DTO

8.5 Feign 客户端复用

@FeignClient(name = "order-svc", path = "/api/v1/orders")
public interface OrderBffClient {
    @GetMapping("/{id}")
    Result<OrderDTO> getById(@PathVariable Long id);
}

@FeignClient(name = "product-svc", path = "/api/v1/products")
public interface ProductBffClient {
    @GetMapping("/{id}")
    Result<ProductDTO> getById(@PathVariable Long id);
}

@FeignClient(name = "user-svc", path = "/api/v1/users")
public interface UserBffClient {
    @GetMapping("/{id}")
    Result<UserDTO> getById(@PathVariable Long id);
}

BFF 层只读聚合为主;写操作仍建议前端或 Gateway 直连 order-svc(避免 BFF 成为写路径单点)。


8.6 并行聚合服务

使用 CompletableFuture 控制超时预算(教学默认 3 秒):

@Service
@RequiredArgsConstructor
public class OrderDetailAggregator {

    private final OrderBffClient orderClient;
    private final ProductBffClient productClient;
    private final UserBffClient userClient;

    @Qualifier("bffExecutor")
    private final Executor bffExecutor;

    public OrderDetailVO aggregate(Long orderId) {
        Result<OrderDTO> orderResult = orderClient.getById(orderId);
        if (!orderResult.isSuccess()) {
            throw new BffException("ORDER_NOT_FOUND", "订单不存在");

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。