在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
💻 作为一名热爱 Java 与软件开发的程序员,我始终相信:清晰的逻辑 + 持续的积累 = 稳健的成长
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕一个常见的开发话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


🍔 Java 实战:外卖配送系统(Spring Cloud Alibaba)

在当今快节奏的生活中,外卖平台已成为人们日常饮食的重要组成部分。从美团、饿了么到达达、闪送,背后都离不开一套高效、稳定、可扩展的分布式系统架构

本文将带你使用 Spring Cloud Alibaba 技术栈,从零构建一个功能完整的外卖配送系统。我们将深入讲解:

  • 🛵 配送流程设计
  • 🏗️ 微服务拆分与架构
  • 🧩 Nacos 服务注册与配置中心
  • 🌐 OpenFeign 服务调用
  • 📊 Sentinel 流量控制与熔断
  • 📦 Seata 分布式事务
  • 📈 Prometheus + Grafana 监控
  • 💬 WebSocket 实时订单状态推送

💡 适合读者:具备 Spring Boot 基础的 Java 开发者,希望通过实战掌握 Spring Cloud Alibaba 在真实业务场景中的应用。


🍕 外卖系统核心流程

一个典型的外卖配送系统包含以下几个核心角色:

  • 👤 用户:下单、支付、查看订单状态
  • 🍳 商家:接单、准备餐品
  • 🚴 配送员:接单、取餐、送达
  • 🧠 系统:订单调度、路径规划、状态管理

🔄 核心业务流程图

用户 商家 配送系统 配送员 提交订单 通知接单 确认接单 智能调度派单 推送配送任务 确认接单 通知配送中 到达取餐 送达 通知已送达 用户 商家 配送系统 配送员

🏗️ 系统架构设计

我们采用 微服务架构,将系统拆分为多个独立服务,通过 Spring Cloud Alibaba 实现服务治理。

📐 整体架构图

前端 App / 小程序
API Gateway
用户服务
商家服务
订单服务
配送服务
支付服务
Nacos
Sentinel
Seata
Prometheus
Grafana
WebSocket
  • Nacos:服务注册与发现 + 配置中心
  • Sentinel:流量控制、熔断降级
  • Seata:分布式事务(AT 模式)
  • Prometheus + Grafana:系统监控
  • WebSocket:实时推送订单状态

🔗 推荐阅读


🛠️ 环境准备

1. 启动 Nacos Server

# 下载 Nacos 2.4.1
wget https://github.com/alibaba/nacos/releases/download/2.4.1/nacos-server-2.4.1.tar.gz
tar -zxvf nacos-server-2.4.1.tar.gz
cd nacos/bin

# 单机模式启动
sh startup.sh -m standalone

访问:http://localhost:8848/nacos
默认账号:nacos / nacos

2. 启动 Sentinel Dashboard

# 下载 Sentinel 控制台
wget https://github.com/alibaba/Sentinel/releases/download/1.8.8/sentinel-dashboard-1.8.8.jar

# 启动
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar

访问:http://localhost:8080
账号:sentinel / sentinel

3. 启动 Seata Server

# 下载 Seata
wget https://github.com/seata/seata/releases/download/v2.0.0/seata-server-2.0.0.tar.gz
tar -zxvf seata-server-2.0.0.tar.gz

# 启动
sh seata-server.sh -p 8091 -m db

⚠️ Seata 使用 db 模式需提前配置 MySQL 数据库,并导入 script/server/db/*.sql


🏗️ 项目结构

外卖系统
├── gateway-api                 # API 网关
├── service-user                # 用户服务
├── service-merchant            # 商家服务
├── service-order               # 订单服务
├── service-delivery            # 配送服务
├── service-payment             # 支付服务
└── common-utils                # 公共工具类

🚀 创建父工程与依赖管理

pom.xml(父工程)

<properties>
    <java.version>17</java.version>
    <spring-boot.version>3.3.3</spring-boot.version>
    <spring-cloud.version>2023.0.3</spring-cloud.version>
    <spring-cloud-alibaba.version>2023.0.3.0</spring-cloud-alibaba.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

🧱 用户服务(service-user)

负责用户注册、登录、信息管理。

1. 引入依赖

<dependencies>
    <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>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

2. 配置文件 bootstrap.yml

spring:
  application:
    name: service-user
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yaml

3. User 实体

@Data
@TableName("t_user")
public class User {
    private Long id;
    private String username;
    private String phone;
    private String address;
    private Integer type; // 1-普通用户, 2-配送员
}

4. UserController

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping("/{id}")
    public Result<User> getUserById(@PathVariable Long id) {
        return Result.success(userService.getById(id));
    }

    @PostMapping
    public Result<User> createUser(@RequestBody User user) {
        userService.save(user);
        return Result.success(user);
    }
}

🔗 MyBatis-Plus 官网https://baomidou.com/


🍔 商家服务(service-merchant)

管理餐厅、菜品、接单状态。

1. MerchantController

@RestController
@RequestMapping("/merchants")
@RequiredArgsConstructor
public class MerchantController {

    private final MerchantService merchantService;

    @GetMapping("/{id}")
    public Result<Merchant> getMerchant(@PathVariable Long id) {
        return Result.success(merchantService.getById(id));
    }

    @PostMapping("/notify")
    public Result<String> notifyOrderReady(@RequestBody OrderNotifyDTO dto) {
        // 商家通知餐品已准备好
        log.info("商家 {} 餐品已准备好,订单ID: {}", dto.getMerchantId(), dto.getOrderId());
        return Result.success("通知成功");
    }
}

📦 订单服务(service-order)

核心服务,负责订单创建、状态流转、调用支付与配送。

1. 订单状态机

public enum OrderStatus {
    CREATED,      // 已创建
    PAID,         // 已支付
    CONFIRMED,    // 商家已接单
    READY,        // 餐品已备好
    DELIVERING,   // 配送中
    DELIVERED,    // 已送达
    CANCELLED     // 已取消
}

2. Order 实体

@Data
@TableName("t_order")
public class Order {
    private Long id;
    private Long userId;
    private Long merchantId;
    private BigDecimal amount;
    private String address;
    private Integer status;
    private LocalDateTime createTime;
}

3. 使用 OpenFeign 调用支付服务

@FeignClient(name = "service-payment")
public interface PaymentClient {

    @PostMapping("/payments/create")
    Result<Payment> createPayment(@RequestBody PaymentRequest request);
}

4. 创建订单(含分布式事务)

@Service
@RequiredArgsConstructor
public class OrderService {

    private final PaymentClient paymentClient;
    private final DeliveryClient deliveryClient;

    @GlobalTransactional // Seata 分布式事务
    public Result<Order> createOrder(OrderDTO orderDTO) {
        // 1. 保存订单
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setMerchantId(orderDTO.getMerchantId());
        order.setAmount(orderDTO.getAmount());
        order.setStatus(OrderStatus.CREATED.getCode());
        save(order);

        // 2. 调用支付服务
        PaymentRequest payReq = new PaymentRequest(order.getId(), order.getAmount());
        Result<Payment> payResult = paymentClient.createPayment(payReq);
        if (!payResult.isSuccess()) {
            throw new RuntimeException("支付失败");
        }

        // 3. 更新订单状态为已支付
        order.setStatus(OrderStatus.PAID.getCode());
        updateById(order);

        // 4. 调用配送服务派单
        DeliveryOrderDTO deliveryDTO = new DeliveryOrderDTO(order.getId(), order.getUserId(), order.getMerchantId());
        Result<String> deliveryResult = deliveryClient.assignDelivery(deliveryDTO);
        if (!deliveryResult.isSuccess()) {
            throw new RuntimeException("派单失败");
        }

        // 5. 更新订单为配送中
        order.setStatus(OrderStatus.DELIVERING.getCode());
        updateById(order);

        return Result.success(order);
    }
}

@GlobalTransactional 注解开启 Seata 的 AT 模式分布式事务,保证订单、支付、配送三个操作的最终一致性。


🚴 配送服务(service-delivery)

负责配送员管理、订单调度、状态更新、实时推送。

1. 配送调度算法(简化版)

@Service
public class DispatchService {

    public DeliveryOrder dispatch(Order order) {
        // 简化逻辑:查找最近的空闲配送员
        List<DeliveryOrder> availableCouriers = courierRepository.findAvailableCouriers();
        
        DeliveryOrder bestCourier = null;
        double minDistance = Double.MAX_VALUE;

        for (DeliveryOrder courier : availableCouriers) {
            double distance = calculateDistance(order.getMerchantAddress(), courier.getCurrentLocation());
            if (distance < minDistance) {
                minDistance = distance;
                bestCourier = courier;
            }
        }

        if (bestCourier != null) {
            bestCourier.setOrderId(order.getId());
            bestCourier.setStatus("ASSIGNED");
            courierRepository.save(bestCourier);
        }

        return bestCourier;
    }

    private double calculateDistance(String addr1, String addr2) {
        // 实际项目应调用高德/百度地图 API
        return Math.random() * 10; // 模拟距离
    }
}

🔗 高德地图 APIhttps://lbs.amap.com/
🔗 百度地图 APIhttps://lbsyun.baidu.com/

2. WebSocket 实时推送

@Component
@ServerEndpoint("/ws/delivery/{orderId}")
public class DeliveryWebSocket {

    private static final Map<Long, Session> sessions = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(@PathParam("orderId") Long orderId, Session session) {
        sessions.put(orderId, session);
        log.info("订单 {} 建立 WebSocket 连接", orderId);
    }

    @OnClose
    public void onClose(@PathParam("orderId") Long orderId) {
        sessions.remove(orderId);
        log.info("订单 {} 断开连接", orderId);
    }

    public static void sendStatusUpdate(Long orderId, String status) {
        Session session = sessions.get(orderId);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(status);
            } catch (IOException e) {
                log.error("推送失败", e);
            }
        }
    }
}

3. 更新配送状态并推送

@PutMapping("/status")
public Result<String> updateStatus(@RequestBody DeliveryStatusDTO dto) {
    DeliveryOrder order = deliveryOrderService.getById(dto.getOrderId());
    order.setStatus(dto.getStatus());
    deliveryOrderService.updateById(order);

    // 实时推送
    DeliveryWebSocket.sendStatusUpdate(dto.getOrderId(), dto.getStatus());

    return Result.success("状态更新成功");
}

前端接收:

const ws = new WebSocket('ws://localhost:8080/ws/delivery/1001');
ws.onmessage = function(event) {
    console.log('订单状态更新:', event.data);
    // 更新 UI
};

🧾 支付服务(service-payment)

模拟支付流程。

@RestController
@RequestMapping("/payments")
public class PaymentController {

    @PostMapping("/create")
    public Result<Payment> createPayment(@RequestBody PaymentRequest request) {
        Payment payment = new Payment();
        payment.setOrderId(request.getOrderId());
        payment.setAmount(request.getAmount());
        payment.setStatus("SUCCESS");
        payment.setPayTime(LocalDateTime.now());

        // 模拟支付成功
        return Result.success(payment);
    }
}

🌐 API 网关(gateway-api)

使用 Spring Cloud Gateway 统一入口、路由、限流。

1. 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2. 配置路由

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: user_service
          uri: lb://service-user
          predicates:
            - Path=/users/**
        - id: order_service
          uri: lb://service-order
          predicates:
            - Path=/orders/**
        - id: delivery_service
          uri: lb://service-delivery
          predicates:
            - Path=/delivery/**

lb:// 表示从 Nacos 获取服务实例并负载均衡。


🛡️ Sentinel 流量控制

1. 在订单服务中引入 Sentinel

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. 配置 Sentinel 控制台地址

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

3. 定义降级逻辑

@FeignClient(name = "service-merchant", fallback = MerchantClientFallback.class)
public interface MerchantClient {
    @PostMapping("/notify")
    Result<String> notifyOrderReady(@RequestBody OrderNotifyDTO dto);
}

@Component
public class MerchantClientFallback implements MerchantClient {
    @Override
    public Result<String> notifyOrderReady(OrderNotifyDTO dto) {
        log.warn("调用商家服务失败,启用降级逻辑,订单ID: {}", dto.getOrderId());
        return Result.success("商家通知已跳过(降级)");
    }
}

4. 在 Sentinel 控制台设置规则

  • 流控规则:/orders/create QPS > 10 时限流
  • 降级规则:异常比例 > 50% 时降级
  • 热点参数:用户 ID 频繁下单时限制

📊 系统监控(Prometheus + Grafana)

1. 在各服务中启用 Actuator + Prometheus

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
management:
  endpoints:
    web:
      exposure:
        include: prometheus,health,metrics
  metrics:
    export:
      prometheus:
        enabled: true

访问:http://localhost:8080/actuator/prometheus

2. 配置 Prometheus

prometheus.yml

scrape_configs:
  - job_name: 'delivery-service'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8081']
  - job_name: 'order-service'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8082']

3. 启动 Prometheus

docker run -d -p 9090:9090 -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus

4. 启动 Grafana

docker run -d -p 3000:3000 grafana/grafana

访问:http://localhost:3000
导入 Spring Boot 监控模板(ID: 12000)


🧪 系统测试流程

1. 启动所有服务

确保 Nacos、Sentinel、Seata、Prometheus、Grafana 已启动。

依次启动:

  • service-user
  • service-merchant
  • service-order
  • service-delivery
  • service-payment
  • gateway-api

2. 创建订单(通过网关)

curl -X POST http://localhost:8080/orders/create \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "merchantId": 1,
    "amount": 58.5,
    "address": "北京市朝阳区xxx"
  }'

3. 查看 Nacos 服务列表

访问:http://localhost:8848/nacos
应看到所有服务注册成功。

4. 查看 Sentinel 实时监控

访问:http://localhost:8080
查看 OrderController.createOrder 的 QPS、响应时间。

5. 模拟配送状态更新

curl -X PUT http://localhost:8080/delivery/status \
  -H "Content-Type: application/json" \
  -d '{"orderId": 1001, "status": "DELIVERING"}'

前端 WebSocket 应收到 "DELIVERING" 消息。


🛠️ 生产环境优化建议

优化项 建议
🚀 性能 使用 Redis 缓存热点数据(如商家信息)
🔐 安全 API 签名、HTTPS、敏感信息加密
📈 扩展性 服务横向扩展,K8s 部署
🔄 高可用 多节点部署 Nacos、Sentinel、Seata
📊 日志 ELK 收集日志,便于排查问题
🔄 CI/CD Jenkins/GitLab CI 自动化部署

📈 未来可扩展功能

  • 🧠 AI 智能调度:基于历史数据预测配送时间
  • 🚗 骑手 App:GPS 实时定位、接单、导航
  • 💬 消息中心:短信、推送通知
  • 📊 数据分析:订单量、配送时长、用户画像
  • 🌐 多语言支持:国际化外卖平台
  • 🤖 无人配送:无人机/机器人配送集成

📚 总结

通过本文的实战,我们使用 Spring Cloud Alibaba 成功构建了一个高可用、可扩展的外卖配送系统,涵盖了:

✅ 微服务拆分与治理
✅ 服务注册与配置(Nacos)
✅ 服务调用(OpenFeign)
✅ 流量控制与熔断(Sentinel)
✅ 分布式事务(Seata)
✅ 实时通信(WebSocket)
✅ 系统监控(Prometheus + Grafana)

这套架构不仅适用于外卖系统,也可用于电商、物流、打车等复杂业务场景。

🔗 延伸学习


🎉 恭喜你,已经掌握了使用 Spring Cloud Alibaba 构建复杂分布式系统的能力!
现在,你可以将这套架构应用于实际项目,打造高性能、高可用的企业级应用。继续探索,不断精进!🚀🍽️🛵


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐