苍穹外卖Day09Day10笔记

苍穹外卖笔记Day09Day10

1. SpringTask 定时任务(苍穹外卖实战)

1.1 基本概念

SpringTask 是 Spring 框架原生自带 的定时任务工具,无需整合 Quartz 等第三方中间件,轻量、简单、开箱即用,专门用于处理苍穹外卖中「周期性、定时执行」的业务场景,无需手动触发,自动按配置时间执行。

1.2 核心作用(苍穹外卖实战场景)

  1. 定时清理:定时清理过期未支付订单(如 30 分钟未支付自动取消)、清理过期优惠券、清理日志数据;
  2. 定时统计:每日凌晨统计前一天的订单量、营业额、用户新增数量,生成运营报表;
  3. 定时同步:定时同步商品库存、同步用户积分、同步配送状态;
  4. 定时提醒:定时提醒商家处理待接单订单、提醒配送员取餐。

1.3 核心注解(必背,面试高频)

(1)@EnableScheduling
  • 作用:开启 SpringTask 定时任务功能,必须加在 SpringBoot 启动类配置类 上,否则定时任务不生效。

  • 苍穹外卖实战示例(启动类):

    java 复制代码
    @SpringBootApplication
    @EnableScheduling // 开启定时任务
    public class SkyApplication {
        public static void main(String[] args) {
            SpringApplication.run(SkyApplication.class, args);
        }
    }
(2)@Scheduled
  • 作用:标记在「要定时执行的方法」上,指定任务的执行时间、频率。

  • 方法要求:无参数、无返回值(void),否则定时任务会报错。

  • 苍穹外卖实战示例(定时取消过期订单):

    java 复制代码
    @Service
    public class OrderServiceImpl implements OrderService {
        // 定时执行:每1分钟检查一次,取消30分钟未支付的订单
        @Scheduled(cron = "0 */1 * * * ?")
        public void cancelExpiredOrder() {
            // 业务逻辑:查询30分钟未支付、未取消的订单,执行取消操作
            List<Order> expiredOrders = orderMapper.selectExpiredUnpaidOrders();
            for (Order order : expiredOrders) {
                order.setStatus(OrderStatus.CANCELLED);
                order.setCancelReason("订单超时未支付,自动取消");
                orderMapper.update(order);
            }
        }
    }

1.4 @Scheduled 三大执行方式(面试重点,区分清楚)

(1)fixedRate:固定频率执行(不推荐用于苍穹外卖核心场景)
  • 核心逻辑:从上一次任务开始执行的时间 计算,每隔指定时间执行一次,无论上一次任务是否执行完毕。
  • 示例:@Scheduled(fixedRate = 5000) → 每 5 秒执行一次,即使上一次任务执行了 3 秒,下一次也会在第 5 秒准时启动。
  • 缺点:如果任务执行时间超过设定频率,会导致任务堆积,占用线程资源,苍穹外卖中很少使用(除非是轻量、快速执行的任务)。
(2)fixedDelay:固定间隔执行(苍穹外卖常用)
  • 核心逻辑:从上一次任务执行结束的时间 计算,等待指定时间后,再执行下一次任务,避免任务堆积。
  • 示例:@Scheduled(fixedDelay = 5000) → 上一次任务执行完后,等待 5 秒,再执行下一次。
  • 适用场景:苍穹外卖中耗时较短的定时任务(如每 10 分钟同步一次库存)。
(3)cron 表达式:精准定时(最常用、面试必问)
  • 核心逻辑:通过表达式,精准控制任务的执行时间(支持秒、分、时、日、月、周、年),功能最强大,适配苍穹外卖中所有复杂定时场景。
  • 语法(7个字段,空格分隔):秒 分 时 日 月 周 年(可选)
    • 通配符说明(面试常考):
      • *:匹配所有值(如秒位写 *,表示每秒执行);
      • ?:仅用于「日」和「周」,表示不指定值(避免日和周冲突);
      • /:表示递增(如 0/5 * * * * ? → 每 5 秒执行一次);
      • -:表示范围(如 0 0 9-18 * * ? → 每天 9 点到 18 点,整点执行);
      • ,:表示多个值(如 0 0 12,18 * * ? → 每天 12 点、18 点各执行一次)。
  • 苍穹外卖常用 Cron 示例(面试必背):
    1. 0 0 2 * * ? → 每天凌晨 2 点(执行日志清理、报表统计);
    2. 0 */1 * * * ? → 每 1 分钟(检查过期订单);
    3. 0 0 0 * * ? → 每天凌晨 0 点(重置当日数据统计);
    4. 0 0 12 * * ? → 每天中午 12 点(推送当日订单统计给商家)。

1.5 SpringTask 执行机制(面试高频,坑点)

(1)默认机制

SpringTask 默认是 单线程执行,所有定时任务共用一个线程;如果一个任务执行时间过长(如清理大量日志耗时 5 分钟),会导致其他定时任务延迟执行,甚至卡死。

(2)多线程配置(生产环境必须配置,苍穹外卖实战)

解决单线程阻塞问题,配置线程池,让不同任务在不同线程中执行,互不影响。

  • 配置类代码(面试可直接写):

    java 复制代码
    @Configuration
    @EnableScheduling
    public class ScheduledConfig implements SchedulingConfigurer {
        // 配置线程池,核心线程数根据任务数量调整(苍穹外卖建议5-10个)
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
        }
    }
  • 面试考点:为什么要配置多线程?答:避免单线程任务阻塞,保证所有定时任务按时执行,提升系统稳定性。

1.6 面试高频问题(结合苍穹外卖)

  1. 苍穹外卖中,SpringTask 用在哪些场景?(答:清理过期订单、统计报表、同步库存、定时提醒);
  2. @EnableScheduling 和 @Scheduled 的作用分别是什么?(答:前者开启定时任务功能,后者标记定时方法);
  3. fixedRate 和 fixedDelay 的区别?(答:前者从任务开始计时,后者从任务结束计时,后者避免堆积);
  4. SpringTask 默认是单线程还是多线程?如何优化?(答:默认单线程,配置线程池优化);
  5. 写出一个"每天凌晨 2 点执行"的 Cron 表达式?(答:0 0 2 * * ?)。

2. WebSocket 详细讲解(苍穹外卖实战)

2.1 基本概念

WebSocket 是一种 全双工、双向通信 的网络协议,基于 TCP 连接,允许客户端(浏览器/APP)和服务器之间建立持久连接,实现「实时通信」------ 服务器可以主动向客户端推送消息,客户端也可以主动向服务器发送消息,无需客户端频繁发起请求(区别于 HTTP 单向通信)。

2.2 核心作用(区别于 HTTP,面试重点)

HTTP 协议是「请求-响应」模式:客户端发起请求,服务器才会返回响应,服务器无法主动向客户端推送消息;

WebSocket 协议是「持久连接」模式:连接建立后,双方可随时互发消息,实时性极高,无需频繁请求,减少网络开销。

2.3 苍穹外卖实战场景(除了实时提醒新订单)

(1)核心场景1:新订单实时提醒(基础)
  • 商家端:用户下单后,服务器通过 WebSocket 实时向商家推送新订单消息(无需商家刷新页面);
  • 配送端:商家接单后,实时向配送员推送待取餐订单,同步订单地址、取餐时间。
(2)核心场景2:订单状态实时同步(高频)
  • 用户端:用户下单后,实时同步订单状态(待接单 → 待配送 → 配送中 → 已完成),无需刷新页面;
  • 商家端:实时同步订单支付状态(未支付 → 已支付)、取消状态,及时处理订单。
(3)核心场景3:实时聊天(苍穹外卖增值功能)
  • 用户与商家聊天:用户咨询菜品、修改订单,商家实时回复;
  • 用户与配送员聊天:用户询问配送进度,配送员实时反馈。
(4)核心场景4:库存实时更新(秒杀/热销场景)
  • 商家端:热销菜品库存不足时,实时推送库存预警(如"番茄炒蛋库存仅剩5份");
  • 用户端:用户下单时,实时推送库存变化(如"库存不足,无法下单")。
(5)核心场景5:实时通知(运营/系统通知)
  • 商家端:平台推送活动通知(如"周末满减活动开启")、违规提醒、系统维护通知;
  • 配送端:推送配送范围调整、配送费调整通知;
  • 用户端:推送优惠券到账、会员权益更新、订单评价提醒。
(6)核心场景6:实时数据统计(商家后台)
  • 商家端实时查看当日订单量、营业额、接单率,数据随订单变化实时更新,无需手动刷新报表。

2.4 WebSocket 核心原理(面试必背)

  1. 握手阶段:客户端发起 HTTP 请求,请求头中携带 Upgrade: websocket,表示要升级为 WebSocket 协议;
  2. 连接建立:服务器响应同意升级,双方建立持久 TCP 连接,后续通信不再使用 HTTP 协议;
  3. 数据传输:连接建立后,客户端和服务器可通过帧(Frame)互发消息,支持文本、二进制数据;
  4. 连接关闭:客户端或服务器主动发送关闭帧,释放连接。

2.5 苍穹外卖 WebSocket 核心实现(简化版,面试可写)

(1)引入依赖(SpringBoot 整合 WebSocket)
xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
(2)配置类(开启 WebSocket 支持)
java 复制代码
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        // 注册 WebSocket 端点,开启 WebSocket 支持
        return new ServerEndpointExporter();
    }
}
(3)WebSocket 核心服务类(处理连接、消息推送)
java 复制代码
// 端点路径:ws://localhost:8080/ws/order/{merchantId}(商家端,按商家ID区分连接)
@ServerEndpoint("/ws/order/{merchantId}")
@Component
public class OrderWebSocketServer {
    // 存储商家ID与对应的WebSocket连接(key:商家ID,value:连接对象)
    private static Map<Long, Session> sessionMap = new ConcurrentHashMap<>();

    // 连接建立时执行(商家打开后台页面,建立连接)
    @OnOpen
    public void onOpen(Session session, @PathParam("merchantId") Long merchantId) {
        sessionMap.put(merchantId, session);
    }

    // 连接关闭时执行(商家关闭页面,释放连接)
    @OnClose
    public void onClose(@PathParam("merchantId") Long merchantId) {
        sessionMap.remove(merchantId);
    }

    // 接收客户端消息(商家发送消息给服务器)
    @OnMessage
    public void onMessage(String message, @PathParam("merchantId") Long merchantId) {
        // 处理商家消息(如确认接单、拒绝订单)
        System.out.println("收到商家" + merchantId + "的消息:" + message);
    }

    // 核心方法:服务器向指定商家推送消息(如新订单提醒)
    public void sendMessage(Long merchantId, String message) {
        Session session = sessionMap.get(merchantId);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
(4)业务层调用(推送新订单消息)
java 复制代码
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderWebSocketServer webSocketServer;

    // 下单成功后,向商家推送新订单消息
    @Override
    public void createOrder(OrderDTO orderDTO) {
        // 1. 生成订单、入库等业务逻辑...
        // 2. 向对应商家推送新订单消息
        Long merchantId = orderDTO.getMerchantId();
        String message = "您有新订单,请及时处理!订单号:" + orderDTO.getOrderNumber();
        webSocketServer.sendMessage(merchantId, message);
    }
}

2.6 面试高频问题(结合苍穹外卖)

  1. WebSocket 和 HTTP 的区别?(答:HTTP 单向请求-响应,无法主动推送;WebSocket 双向全双工,持久连接,实时性高,减少请求开销);
  2. 苍穹外卖中,WebSocket 除了新订单提醒,还有哪些用途?(答:订单状态同步、实时聊天、库存预警、实时通知、数据统计);
  3. WebSocket 连接建立的过程?(答:客户端发起 HTTP 升级请求 → 服务器响应升级 → 建立 TCP 持久连接);
  4. 如何保证 WebSocket 连接的稳定性?(答:心跳检测、重连机制、异常关闭时释放连接);
  5. 苍穹外卖中,如何区分不同商家的 WebSocket 连接?(答:通过商家ID作为key,存储连接对象,推送消息时根据商家ID定位连接)。

3. 总结(面试重点)

  1. SpringTask:Spring 原生定时工具,核心注解 @EnableScheduling + @Scheduled,三大执行方式(fixedRate、fixedDelay、cron),必须配置多线程避免阻塞,苍穹外卖主要用于定时清理、统计、同步任务;
  2. WebSocket:双向实时通信协议,核心是持久连接,苍穹外卖除新订单提醒,还用于订单状态同步、实时聊天、库存预警等场景,核心实现是端点配置 + 连接管理 + 消息推送;
  3. 两者关联:SpringTask 可定时触发 WebSocket 消息推送(如每天中午推送订单统计),共同支撑苍穹外卖的定时、实时业务需求。
相关推荐
鱼鳞_2 小时前
Java学习笔记_Day35(多线程)
java·笔记·学习
23471021272 小时前
4.20 学习笔记
软件测试·笔记·python·学习
哥本哈士奇2 小时前
SQLAlchemy 学习笔记
笔记·学习
呼叫冰河谷3 小时前
Unity学习笔记(六)——3DRPG游戏(4)
笔记·学习·游戏
qeen873 小时前
【算法笔记】前缀和经典题目解析
c语言·c++·笔记·学习·算法
Je1lyfish3 小时前
Haskell 初探
开发语言·笔记·算法·rust·lisp·抽象代数
Aliex_git3 小时前
前端监控笔记(三)
前端·笔记·学习
zzb15803 小时前
Kotlin 密封类与延迟初始化学习笔记
笔记·学习·kotlin
三品吉他手会点灯3 小时前
C语言学习笔记 - 2.C概述 - HelloWorld程序举例
c语言·笔记·学习