Java 23 种设计模式:从踩坑到精通 | 番外:单例模式 —— 全局唯一物流配置中心实战 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智能调度实战》、《电商多平台电子面单对接实战》。技术相通思路可鉴。

本月热点