JAVA 17函数式编程 + Lambda表达式实现的无侵入式设计

一、传统侵入式设计的弊端

1.1 真实业务场景

在零售连锁系统中,门店对配货单进行收货时存在双重收货机制:

机制1:店员手动收货

  • 门店店员在系统中点击”确认收货”按钮
  • 系统根据实际收货数量更新配货单明细
  • 更新配货单状态

机制2:系统自动收货

  • 定时任务每天中午12点扫描所有未收货的配货单
  • 如果配货单的”预计送达日期”已过,系统自动触发收货流程
  • 按照发货数量自动生成收货记录

并发冲突场景: 假设某配货单的预计送达日期是”2025-12-16”,在12月16日中午:

  • 12:00:03 - 定时任务扫描到该配货单,开始执行自动收货
  • 12:00:04 - 门店店员恰好在系统中点击”确认收货”

不加锁的后果:

  • 配货单明细的收货数量被重复更新(实际收货100件,但记录显示200件)
  • 生成两条收货记录

解决方案:使用分布式锁,同一配货单同一时刻只能执行一次收货操作(无论人工还是自动)。

1.2 传统写法示例

在传统的分布式锁实现中,我们通常会将锁逻辑直接写在业务方法内部:

@Slf4j @Service public class DeliveryReceiveService { @Autowired private RedissonClient redissonClient; @Autowired private DeliveryDocsMapper deliveryDocsMapper; @Autowired private DeliveryDocsItemMapper deliveryDocsItemMapper; /** * 店员手动收货(入口1) */ public void confirmReceive(String docsNo, List<ReceiveItem> items) { // 调用统一的收货逻辑 processReceive(docsNo, items); } /** * 系统自动收货(入口2) */ public void autoReceive(String docsNo) { // 查询配货单明细 List<DeliveryDocsItem> itemList = deliveryDocsItemMapper.selectByDocsNo(docsNo); // 按发货数量生成收货明细 List<ReceiveItem> items = itemList.stream() .map(item -> new ReceiveItem(item.getMaterialId(), item.getShippedNum())) .collect(Collectors.toList()); // 调用统一的收货逻辑 processReceive(docsNo, items); } /** * 统一的收货处理逻辑(传统侵入式写法) * 核心业务方法,所有收货操作最终都调用这里 */ private void processReceive(String docsNo, List<ReceiveItem> items) { // 拼接锁的key:按配货单号加锁 String lockKey = "delivery:receive:" + docsNo; RLock rLock = redissonClient.getLock(lockKey); try { // 尝试获取锁,获取不到直接失败(不等待) boolean locked = rLock.tryLock(0, TimeUnit.MILLISECONDS); if (!locked) { throw new RuntimeException("配货单正在收货中,请稍后再试"); } // ========== 真正的业务逻辑开始 ========== // 1. 查询配货单 DeliveryDocs docs = deliveryDocsMapper.selectByDocsNo(docsNo); if (docs == null) { throw new RuntimeException("配货单不存在"); } // 2. 校验配货单状态 if ("RECEIVED".equals(docs.getStatus())) { throw new RuntimeException("配货单已收货,请勿重复操作"); } // 3. 更新明细的收货数量 for (ReceiveItem item : items) { deliveryDocsItemMapper.updateReceiveNum( docsNo, item.getMaterialId(), item.getReceiveNum() ); } // 4. 更新配货单状态 docs.setStatus("RECEIVED"); docs.setReceiveTime(new Date()); deliveryDocsMapper.updateById(docs); // ========== 真正的业务逻辑结束 ========== } catch (RuntimeException re) { throw re; } catch (Exception e) { log.error("收货失败, docsNo:{}", docsNo, e); throw new RuntimeException("收货失败,请稍后重试"); } finally { // 释放锁 if (rLock.isHeldByCurrentThread()) { rLock.unlock(); } } } }

1.3 传统写法的三大弊端

弊端1:代码重复

每个需要加锁的方法都要重复写20+行锁相关代码(获取锁、try-catch、finally释放锁),违反DRY原则。

弊端2:业务逻辑被淹没

真正的业务代码被大量锁逻辑包裹,锁代码占比高达40-50%,可读性极差。

弊端3:维护成本高

  • 如果要修改锁的超时时间,需要改动所有方法(10个方法 = 10处修改)
  • 如果要添加锁获取失败的监控日志,需要改动所有方法
  • 新增需要加锁的方法时,必须复制粘贴20+行代码
  • 极易出现复制粘贴导致的bug(忘记修改lockKey、忘记释放锁等)

二、无侵入式设计原理

2.1 核心思想

将业务逻辑作为参数传入通用方法,通用方法负责锁的管理

2.2 实现机制

步骤1:封装通用工具类

为了让所有业务类都能复用,我们将锁逻辑封装为独立的工具类:

@Slf4j @Component @RequiredArgsConstructor public class DistributedLockUtil { private final RedissonClient redissonClient; /** * 执行带分布式锁的业务逻辑(不等待) * * @param lockKey 锁的key * @param task 要执行的业务逻辑 */ public void executeWithLock(String lockKey, Runnable task) { executeWithLock(lockKey, 0, TimeUnit.MILLISECONDS, task); } /** * 执行带分布式锁的业务逻辑(可设置等待时间) * * @param lockKey 锁的key * @param waitTime 等待锁的时间 * @param timeUnit 时间单位 * @param task 要执行的业务逻辑 */ public void executeWithLock(String lockKey, long waitTime, TimeUnit timeUnit, Runnable task) { RLock rLock = redissonClient.getLock(lockKey); try { boolean locked = rLock.tryLock(waitTime, timeUnit); if (locked) { task.run(); } else { throw new BusinessException("正在处理中,请稍后再试"); } } catch (BusinessException be) { throw be; } catch (Exception e) { log.error("执行失败, lockKey:{}", lockKey, e); throw new BusinessException("操作失败,请稍后重试"); } finally { if (rLock.isHeldByCurrentThread()) { rLock.unlock(); } } } }

步骤2:业务类注入工具类

@Service @RequiredArgsConstructor public class DeliveryReceiveService { private final DistributedLockUtil distributedLockUtil; // 注入工具类 private final DeliveryDocsMapper deliveryDocsMapper; /** * 店员手动收货 */ public void confirmReceive(String docsNo, List<ReceiveItem> items) { String lockKey = "delivery:receive:" + docsNo; // 直接调用工具类方法 distributedLockUtil.executeWithLock(lockKey, () -> processReceive(docsNo, items)); } }

好处

  • 全局复用:所有Service类都可以注入DistributedLockUtil使用
  • 统一维护:修改锁逻辑只需改一个类
  • 更加清晰:业务类不再有锁相关的代码
  • 灵活配置:支持自定义等待时间,适应不同业务场景

步骤3:业务方法保持纯净

/** * 统一的收货处理逻辑(纯业务逻辑,无锁代码) */ private void processReceive(String docsNo, List<ReceiveItem> items) { // 1. 查询配货单 DeliveryDocs docs = deliveryDocsMapper.selectByDocsNo(docsNo); if (docs == null) { throw new RuntimeException("配货单不存在"); } // 2. 校验配货单状态 if ("RECEIVED".equals(docs.getStatus())) { throw new RuntimeException("配货单已收货,请勿重复操作"); } // 3. 更新明细的收货数量 for (ReceiveItem item : items) { deliveryDocsItemMapper.updateReceiveNum( docsNo, item.getMaterialId(), item.getReceiveNum() ); } // 4. 更新配货单状态 docs.setStatus("RECEIVED"); docs.setReceiveTime(new Date()); deliveryDocsMapper.updateById(docs); }

步骤4:调用时使用Lambda表达式

/** * 店员手动收货(对外接口) */ public void confirmReceive(String docsNo, List<ReceiveItem> items) { String lockKey = "delivery:receive:" + docsNo; // 使用Lambda表达式将业务逻辑封装为Runnable传入 distributedLockUtil.executeWithLock(lockKey, () -> processReceive(docsNo, items)); }

2.3 Lambda表达式的魔法

Lambda表达式本质

() -> processReceive(docsNo, items)

等价于创建一个匿名类实例:

new Runnable() { @Override public void run() { processReceive(docsNo, items); } }

执行流程图


三、无侵入式设计的优势

对比维度传统侵入式无侵入式提升
锁逻辑复用性❌ 每个方法重复✅ 统一封装100%复用
可维护性❌ 修改影响所有方法✅ 只修改通用方法维护点从N个降为1个
可测试性❌ 难以单独测试业务逻辑✅ 业务方法独立可测测试复杂度降低

四、总结

4.1 技术要点

  1. 函数式接口:Runnable(无返回值)
  2. Lambda表达式() -> method()简化匿名类创建
  3. 高阶函数:将函数作为参数传递

4.2 适用场景

  • ✅ 分布式锁管理

4.3 核心价值

价值维度说明
代码简洁业务方法只保留业务逻辑,非业务代码统一封装
高度复用通用方法可被所有业务方法复用
易于维护修改锁逻辑只需改一处,影响范围可控
职责清晰业务逻辑与基础设施逻辑完全分离
测试友好业务方法可独立测试,无需Mock锁

通过函数式编程和Lambda表达式,我们实现了真正的无侵入式设计,让代码更加优雅、简洁、易维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1205390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026年盐城有名的高考复读机构排名,鸿文位居前列

2026年新高考改革持续深化,优质复读资源已成为考生实现分数跃迁、名校梦想的关键支撑。无论是中高考复读的精准提分、艺考文化课的靶向突破,还是全周期升学规划指导,专业机构的教学实力直接决定复读生的备考效率与升…

物料粉磨系统

2 结构设计[1] 2.1 总体设计 2.1.1 确定总体结构的组成 新型组合式选粉机可看作笼式高效选粉机和粗粉分离器以及旋风收尘器的紧凑组合。主体分为上下两部分&#xff0c;上部是笼式高效选粉机&#xff0c;为分级核心&#xff1b;下部相当于粗粉分离器&#xff0c;用于初步处理含…

2025年国内诚信的人形机器人关节电机产品推荐榜,人形机器人关节电机/关节电机,人形机器人关节电机厂家哪家好

随着全球人形机器人产业进入爆发期,关节电机作为实现高精度运动控制的核心部件,其技术迭代与供应链稳定性直接影响机器人性能。据行业数据,2024年国内人形机器人关节电机市场规模达32亿元,预计2027年将突破80亿元,…

铣床专用主轴箱设计

1.概述 1.1铣削专用主轴箱设计的目的 课程设计是在金属切削机床课程之后进行的实践性教学环节。其目的在于通过机床运动机械变速传动系统的结构设计&#xff0c;使学生在拟定传动和变速的结构的结构方案过程中&#xff0c;得到设计构思&#xff0c;方案分析&#xff0c;结构工艺…

Excel文件LabVIEW库,xlsx格式,可读可写可设置颜色,运行稳定,源代码提供

Excel文件LabVIEW库&#xff0c;xlsx格式&#xff0c;可读可写可设置颜色&#xff0c;运行稳定&#xff0c;源代码提供。 被LabVIEW自带的Excel操作坑过的请举手&#xff01;那个需要依赖Office版本的老古董Report Generation Toolkit&#xff0c;还有动不动就崩溃的VI&#x…

追求雅思高分?2026全国优质出国雅思机构实测,9分+机构助你高效通关

IDP教育集团《2026全球雅思考试趋势报告》显示,中国雅思考生规模年增12%,出国雅思培训需求攀升,但备考与选课痛点突出。无论是北京海淀区、上海徐汇区、广州天河区、深圳南山区等热门留学区县,还是成都锦江区、武汉…

蜗杆传动设计

3.1 蜗杆传动的类型 根据蜗杆形状的不同&#xff0c;蜗杆传动可以分为圆柱蜗杆传动&#xff0c;环面蜗杆传动和锥蜗杆传动等。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/25b54ec648b647379fac43896c7f8100.png)图3-1 蜗轮蜗杆传动图 3.1.1圆柱蜗杆传动 圆柱蜗杆…

2026渗透测试零基础入门教程(超详细)从入门到精通,收藏这篇就够了!

1. 什么是渗透测试 渗透测试就是模拟真实黑客的攻击手法对目标网站或主机进行全面的安全评估&#xff0c;与黑客攻击不一样的是&#xff0c;渗透测试的目的是尽可能多地发现安全漏洞&#xff0c;而真实黑客攻击只要发现一处入侵点即可以进入目标系统。 一名优秀的渗透测试工程…

The 4th Universal Cup. Stage 8: Grand Prix of Poland

Preface 不知道 VP 什么还是选了这赛季的外国场 UCUP,毕竟还是正规区域赛题目质量还是有保障的 就是整体难度相对偏低,签到和前期题比较多,同时算法题相对较少,不过这些问题也是老生常谈了A. AIMPPZ 签到,枚举有几…

拒绝踩坑!全国雅思培训机构全面深度测评,高性价比提分方案汇总

雅思考试作为全球认可度最高的语言能力测试之一,是学生留学、职场晋升的必经之路,但雅思培训选课难、提分慢、机构鱼龙混杂等问题,一直困扰着广大考生。无论是北京海淀区、上海徐汇区,还是广州天河区、成都锦江区、…

挖掘机毕业设计

第1章 设计计算的内容和步骤 液压系统有液压传动系统和液压控制系统之分。前者以传递动力为主&#xff0c;追求传动特性的完善&#xff1b;后者以实施控制为主&#xff0c;追求控制特性的完善。但从结构和组成原理看&#xff0c;二者无本质的差别。本次设计&#xff0c;是液压传…

网络安全渗透测试:从入门到实践,什么是网络安全渗透测试?渗透测试的实际应用一文解析

网络安全渗透测试&#xff1a;从入门到实践 网络安全渗透测试&#xff08;Penetration Testing&#xff0c;简称Pen Test&#xff09;是现代网络安全领域中不可或缺的一部分。它通过模拟黑客攻击的方式&#xff0c;帮助企业和组织发现系统中的安全漏洞&#xff0c;从而提升整体…

全国雅思培训哪里好?权威深度测评TOP5榜单,精准选课不踩坑

雅思培训市场竞争激烈,全国雅思考生普遍面临备考与选课难题。无论是北京朝阳、上海浦东、广州天河等核心城区,优质雅思教育机构扎堆却良莠不齐,考生难以筛选靠谱选项;还是成都都江堰、武汉洪山、深圳南山等远郊区县…

lectrue7 哈希表

数据结构&#xff1a;DBMS在系统内部的许多不同部分使用各种数据结构&#xff0c;一些例子包括&#xff1a;内部元数据 (Internal Meta-Data)&#xff1a;用于跟踪关于数据库和系统状态信息的数据。例如&#xff1a;页表 (Page tables)、页目录 (Page directories)。核心数据存…

合肥腹直肌修复服务哪家合适,合肥妈妈值得推荐

在产后恢复的关键阶段,腹直肌康复修复是许多宝妈重塑体态、重拾自信的核心需求。面对市场上琳琅满目的腹直肌修复服务,腹直肌修复服务哪家便宜腹直肌修复服务哪家合适成为宝妈们热议的话题。以下结合服务类型与真实口…

同步电机模型的MATLAB仿真

第2章同步电机基本原理 2.1理想同步电机 2.1.1理想同步电机假设 众所周知&#xff0c;由于转子结构的不同&#xff0c;同步电机可分为隐极机和凸极机两类。以下的研究对象像都是凸极机。 同步电机的主要特点是&#xff1a;定子有三相交流绕组&#xff0c;转子为直流励磁。 将电…

2026出国雅思培训机构权威测评榜单:TOP5深度解析,精准选课不踩坑

英国文化教育协会数据显示,中国雅思考生平均备考周期9.2个月,43%需二次及以上考试,其中北京朝阳区、上海静安区、广州天河区、深圳南山区、杭州西湖区、成都锦江区等全国多地区区县考生,普遍面临雅思培训选课难、找…

基于DSP28335 SCI模块控制ESP8266 WiFi模块的实现方案

一、硬件连接与配置硬件接口定义DSP28335引脚 ESP8266引脚 功能说明SCITXDA RX DSP发送数据到ESP8266SCIRXDA TX ESP8266发送数据到DSPGND GND 共地VCC 3.3V 供电(需电平转换芯片)关键配置参数系统时钟:假设SYSCLKO…

盘点盐城有实力的中考复读品牌学校,鸿文复读口碑良好

2026年江苏中考竞争持续白热化,部分考生因发挥失常、基础薄弱与理想高中失之交臂,中考复读成为重启升学梦想的关键选择。然而,当前市场中中考复读机构鱼龙混杂:部分机构缺乏正规资质,教学体系松散;另有机构师资不…