Java 23 种设计模式从踩坑到精通 | 番外单例模式 —— 全局唯一物流配置中心实战摘要单例模式确保一个类在全局只有一个实例常用于管理配置、连接池等共享资源。本文结合智能物流中的“全局物流配置中心”场景从双重检查锁DCL、静态内部类到枚举实现完整展示单例的 5 种写法同时深入剖析多线程安全、反射攻击、反序列化陷阱等踩坑点并给出 Spring 环境下的替代方案帮你彻底掌握“全局唯一”的设计精髓。《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 正篇Singleton —— 你写的单例真的安全吗 当前番外 · 单例模式 × 物流配置中心 返回系列总目录1. 物流配置中心的痛点在物流平台中全局配置中心需要被订单服务、追踪服务、调度服务等多个模块共享。如果每个模块都自己创建配置实例会导致配置信息不一致、内存浪费、文件重复读取等问题。单例模式可以确保全局只有一个配置中心实例所有模块共享同一份配置数据。2. 单例模式 UML物流场景版3. 完整源码实现3.1 单例类物流配置中心DCL 实现importjava.util.HashMap;importjava.util.Map;/** * 单例类物流配置中心 * 使用双重检查锁Double-Checked Locking实现线程安全的懒加载单例 */publicclassLogisticsConfigCenter{// volatile 保证多线程下的可见性和禁止指令重排序privatestaticvolatileLogisticsConfigCenterinstance;// 锁对象privatestaticfinalObjectlocknewObject();// 配置存储privatefinalMapString,StringconfigMap;/** * 私有构造方法防止外部实例化 */privateLogisticsConfigCenter(){System.out.println([单例] 正在初始化物流配置中心...);this.configMapnewHashMap();// 模拟从配置文件/配置中心加载配置loadDefaultConfig();}/** * 加载默认配置模拟从配置中心读取 */privatevoidloadDefaultConfig(){configMap.put(api.key.sms,SMS_2026_ALIYUN_KEY);configMap.put(api.key.map,MAP_2026_GAODE_KEY);configMap.put(thread.pool.size,20);configMap.put(warehouse.endpoint,https://warehouse.logistics.com/api);configMap.put(tracking.endpoint,https://tracking.logistics.com/api);configMap.put(order.timeout.minutes,30);}/** * 获取单例实例双重检查锁实现 * return 全局唯一的配置中心实例 */publicstaticLogisticsConfigCentergetInstance(){// 第一次检查避免不必要的同步if(instancenull){synchronized(lock){// 第二次检查确保只有一个线程创建实例if(instancenull){instancenewLogisticsConfigCenter();}}}returninstance;}/** * 获取配置项 */publicStringgetApiKey(Stringservice){returnconfigMap.get(api.key.service);}publicintgetThreadPoolSize(){returnInteger.parseInt(configMap.getOrDefault(thread.pool.size,10));}publicStringgetWarehouseEndpoint(){returnconfigMap.get(warehouse.endpoint);}/** * 刷新配置模拟动态刷新 */publicvoidrefreshConfig(){System.out.println([单例] 正在刷新配置...);configMap.clear();loadDefaultConfig();System.out.println([单例] 配置刷新完成);}/** * 防止反序列化破坏单例 */privateObjectreadResolve(){returngetInstance();}}3.2 客户端 A订单处理服务/** * 客户端A订单处理服务 */publicclassOrderProcessingService{publicvoidprocessOrder(StringorderId){System.out.println(\n【订单处理】处理订单orderId);// 从单例配置中心获取配置LogisticsConfigCenterconfigLogisticsConfigCenter.getInstance();intpoolSizeconfig.getThreadPoolSize();StringwarehouseEndpointconfig.getWarehouseEndpoint();System.out.println( → 线程池大小poolSize);System.out.println( → 仓库服务地址warehouseEndpoint);System.out.println( → 订单处理完成 ✓);}}3.3 客户端 B物流追踪服务/** * 客户端B物流追踪服务 */publicclassTrackingService{publicvoidtrackPackage(StringtrackingNo){System.out.println(\n【物流追踪】追踪单号trackingNo);// 从同一个单例配置中心获取配置LogisticsConfigCenterconfigLogisticsConfigCenter.getInstance();StringtrackingEndpointconfig.getApiKey(map);System.out.println( → 地图API KeytrackingEndpoint);System.out.println( → 追踪信息已更新 ✓);}}3.4 完整测试验证/** * 测试类验证单例的唯一性 */publicclassSingletonTest{publicstaticvoidmain(String[]args)throwsInterruptedException{System.out.println( 单例模式物流配置中心 \n);// 验证1多次获取实例地址应该相同LogisticsConfigCenterc1LogisticsConfigCenter.getInstance();LogisticsConfigCenterc2LogisticsConfigCenter.getInstance();System.out.println(\n[验证1] 实例地址是否相同);System.out.println( c1 c1);System.out.println( c2 c2);System.out.println( c1 c2 ? (c1c2));// 验证2多线程环境下是否仍为单例System.out.println(\n[验证2] 多线程获取实例...);Threadt1newThread(()-{LogisticsConfigCenterinstanceLogisticsConfigCenter.getInstance();System.out.println( 线程1获取实例instance);});Threadt2newThread(()-{LogisticsConfigCenterinstanceLogisticsConfigCenter.getInstance();System.out.println( 线程2获取实例instance);});t1.start();t2.start();t1.join();t2.join();// 验证3不同业务模块使用同一个配置中心System.out.println(\n[验证3] 不同模块共享配置中心...);OrderProcessingServiceorderServicenewOrderProcessingService();TrackingServicetrackingServicenewTrackingService();orderService.processOrder(ORD20260723001);trackingService.trackPackage(TRACK20260723001);}}4. 运行结果 单例模式物流配置中心 [单例] 正在初始化物流配置中心... [验证1] 实例地址是否相同 c1 LogisticsConfigCenter1b6d3586 c2 LogisticsConfigCenter1b6d3586 c1 c2 ? true [验证2] 多线程获取实例... 线程1获取实例LogisticsConfigCenter1b6d3586 线程2获取实例LogisticsConfigCenter1b6d3586 [验证3] 不同模块共享配置中心... 【订单处理】处理订单ORD20260723001 → 线程池大小20 → 仓库服务地址https://warehouse.logistics.com/api → 订单处理完成 ✓ 【物流追踪】追踪单号TRACK20260723001 → 地图API KeyMAP_2026_GAODE_KEY → 追踪信息已更新 ✓5. 单例的五种实现对比实现方式线程安全懒加载推荐度说明饿汉式✅❌⭐⭐类加载时创建简单但浪费资源懒汉式同步方法✅✅⭐⭐每次访问都加锁性能差双重检查锁DCL✅✅⭐⭐⭐⭐⭐兼顾性能与线程安全推荐静态内部类✅✅⭐⭐⭐⭐⭐利用类加载机制简洁优雅枚举✅✅⭐⭐⭐⭐⭐天生防反射/序列化攻击静态内部类实现另一种推荐写法publicclassLogisticsConfigCenter{privateLogisticsConfigCenter(){/* 初始化 */}privatestaticclassHolder{privatestaticfinalLogisticsConfigCenterINSTANCEnewLogisticsConfigCenter();}publicstaticLogisticsConfigCentergetInstance(){returnHolder.INSTANCE;}}枚举实现最安全publicenumLogisticsConfigCenter{INSTANCE;publicvoiddoSomething(){/* 业务方法 */}}6. 单例模式的“坑”与防御攻击方式防御手段反射构造器内判断实例是否已存在抛异常序列化实现readResolve()返回已有实例克隆重写clone()抛异常或返回自身7. 单例模式 vs Spring Bean对比项手写单例Spring singleton scope实现方式代码层面保证容器层面保证测试友好度差好支持依赖注入和 Mock推荐场景简单工具类企业级项目首选 在 Spring 项目中优先使用容器的 singleton scope而不是手写单例。8. 六大设计原则体现原则体现单一职责配置中心只负责管理配置开闭原则可通过枚举、静态内部类扩展实现里氏替换枚举单例可替换父类依赖倒置Spring 容器依赖抽象而非具体单例接口隔离通过getInstance暴露最小接口迪米特法则客户端只需知道getInstance一个入口单例模式 UML源代码物流场景版startuml title Java 23 种设计模式从踩坑到精通 footer 折哥 | 智能物流与Java实战 skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam classBorderColor #333333 skinparam classFontColor #1A1A1A skinparam classFontSize 14 skinparam noteFontSize 12 skinparam noteFontColor #555555 skinparam arrowColor #555555 skinparam classBackgroundColor #F9F9F9 class LogisticsConfigCenter { - {static} volatile instance : LogisticsConfigCenter - {static} final Object lock - LogisticsConfigCenter() {static} getInstance() : LogisticsConfigCenter -- String getApiKey(String service) int getThreadPoolSize() String getWarehouseEndpoint() void refreshConfig() } note right of LogisticsConfigCenter b单例类Singleton/b -- 全局唯一的物流配置中心 统一管理所有物流服务的配置信息 采用双重检查锁DCL实现线程安全 end note class OrderProcessingService { void processOrder(String orderId) } note right of OrderProcessingService b客户端Client/b -- 多个业务模块通过 getInstance() 获取同一个配置中心实例 end note class TrackingService { void trackPackage(String trackingNo) } note right of TrackingService b客户端Client/b -- 追踪服务同样共享同一个 配置中心实例 end note OrderProcessingService .. LogisticsConfigCenter : 获取配置 TrackingService .. LogisticsConfigCenter : 获取配置 enduml 《Java 23 种设计模式从踩坑到精通》快速导航开篇系列介绍与目录正篇Singleton —— 你写的单例真的安全吗当前番外 · 单例模式 × 物流配置中心你在这里创建型模式汇总结构型模式汇总行为型模式汇总 关注《Java 23 种设计模式从踩坑到精通》用 25 篇文章彻底吃透设计模式。福利预告全系列代码及 UML 源码将在完结时统一打包开放点击「关注」「收藏」第一时间获取。 除了设计模式我也在深挖智能物流实战WMS、托盘调度、机器学习落地。欢迎点击头像看看专栏 《出版社物流WMS智能调度实战》、《电商多平台电子面单对接实战》。技术相通思路可鉴。
企业数字化 ERP 产品动态
相关推荐
光电幕墙简介 光电幕墙 光电幕墙,即粘贴在玻璃上,镶嵌于两片玻璃之间,通过电池可将光能转化成电能。这就是--太阳能光电幕墙。它是用光电池、光电板技术,把太阳光转化为电能,它关键的技术是太阳能光电池技术。太阳能光电池是利用太阳光的光子能量,使得被照射的电解液或者半导体材料的电… · 2026/9/19 12:57:47
工业一体机Linux系统部署实战:从系统安装到工业通信环境搭建 工业一体机是面向工业场景的集成化计算终端,通常预装Windows或Linux操作系统,支持串口通信、GPIO控制、工业总线协议等工业级接口。在ARM架构工业一体机上部署Linux系统并搭建工业通信开发环境,是工业自动化项目的常见基础工作。之前在项目里… · 2026/9/16 2:55:52
Kimi K3引发华尔街震动:算力转化与商业化双突破,重塑行业估值逻辑? 让华尔街紧张的,其实是Kimi K3的算力转化效率?最近一周,华尔街陷入对芯片产业的“信任危机”。费城半导体指数一周内跌12.5%入技术性熊市,17家投行下调AI芯片企业目标价,高盛称“算力扩张时代”或近尾声。震荡源于月之… · 2026/9/18 22:59:59
Spingboot启动预热的实现 启动预热的适用场景启动预热适合以下情况:数据主要来自第三方接口,无法直接从本地数据库读取。第三方接口响应较慢,首次访问容易超时。一个页面需要调用多个第三方接口或逐项查询。数据读取频繁,但变化不频繁。希望服务启动后&… · 2026/9/29 6:52:37
学Java别走弯路,这5个方向最吃香 学Java的人很多,但学明白的人不多。有人学了半年还在写控制台程序,有人一年就能独当一面。差别不在天赋,而在方向。Java生态太庞大了,什么都学等于什么都没学。选对方向,事半功倍。今天盘点当前最吃香的5个Java方向&am… · 2026/9/29 4:13:53
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/29 0:45:26
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/29 13:54:52
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/29 8:55:58