吉安网站推广,免费seo在线优化,做cps要做什么类型的网站,wordpress 调用评论数文章目录前言背景初步调研实现思路方案核心需求分析技术方案对比实现思路初步功能设计关键设计决策实现步骤与代码第一步#xff1a;核心关闭管理器实现第二步#xff1a;集成到钉钉客户端管理器#xff08;注册关闭#xff09;总结说明资料获取前言
博主介绍#xff1a;…文章目录前言背景初步调研实现思路方案核心需求分析技术方案对比实现思路初步功能设计关键设计决策实现步骤与代码第一步核心关闭管理器实现第二步集成到钉钉客户端管理器注册关闭总结说明资料获取前言博主介绍✌目前全网粉丝4Wcsdn博客专家、Java领域优质创作者博客之星、阿里云平台优质作者、专注于Java后端技术领域。涵盖技术内容Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。博主所有博客文件目录索引博客目录索引(持续更新)CSDN搜索长路视频平台b站-Coder长路背景在企业级应用开发中服务的稳定性和可靠性是至关重要的考量因素。在实际生产环境中应用经常会遇到各种异常情况内存溢出导致JVM崩溃、系统资源耗尽触发强制重启、部署平台主动销毁容器实例等。这些异常退出场景往往使得应用无法正常执行资源清理操作进而引发一系列严重问题数据库连接池连接未释放导致连接泄漏网络长连接如WebSocket、钉钉Stream连接未正常关闭文件句柄未释放造成资源浪费消息队列消费者未正确取消订阅分布式锁未释放引发死锁问题近期在开发钉钉机器人集成服务时我们就遇到了这样一个具体问题当应用异常重启时如何确保所有已建立的钉钉Stream模式客户端连接能够被正确关闭这不仅关系到系统资源的有效管理更直接影响整个服务的稳定性和可维护性。初步调研实现思路方案核心需求分析通过对问题的深入剖析识别出以下几个本质需求1. 异常退出的可靠捕获// 伪代码我们需要捕获的信号包括// - 正常关闭: kill -15// - 强制杀死: kill -9 (无法捕获)// - CtrlC中断// - 系统资源耗尽// - 代码异常导致JVM退出2. 统一资源管理接口// 期望的使用方式应该是简单一致的resourceManager.register(resourceId,()-{// 关闭逻辑connection.close();fileHandle.release();lock.unlock();});3. 执行顺序和异常隔离关闭操作应该顺序执行避免并发问题单个资源的关闭异常不应影响其他资源需要有完善的日志记录和错误处理4. 与业务代码解耦// 不好的做法关闭逻辑散落在各个业务类中publicclassDingTalkClient{publicvoidclose(){// 关闭逻辑}}// 好的做法统一注册集中管理技术方案对比基于核心需求评估了多种技术方案方案一手动关闭管理// 优点控制精确// 缺点容易遗漏无法处理异常退出publicclassManualShutdown{publicvoidshutdown(){client1.close();client2.close();// 可能遗漏client3}}方案二Spring框架管理ComponentpublicclassSpringManagedBean{PreDestroypublicvoiddestroy(){// 关闭逻辑}}// 缺点依赖Spring容器无法处理容器外异常方案三JVM Shutdown HookRuntime.getRuntime().addShutdownHook(newThread(()-{// 关闭逻辑}));// 优点能捕获大多数异常退出场景// 缺点需要自行管理注册和执行方案四第三方库Apache Commons Daemon功能强大但配置复杂Airline轻量级但功能有限经过综合评估决定基于JVM Shutdown Hook构建自定义解决方案它能够在保证功能完整性的同时提供最大的灵活性和可控性。实现思路初步功能设计设计一个分层架构的关闭管理系统注册层提供简洁的API用于注册关闭操作管理层维护关闭操作的有序集合处理并发安全执行层在适当时机顺序执行所有关闭操作容错层确保单个操作的失败不影响整体关闭流程关键设计决策1. 单例模式确保全局唯一// 确保整个JVM中只有一个关闭管理器实例publicclassShutdownManager{privatestaticfinalShutdownManagerINSTANCEnewShutdownManager();}2. 线程安全的数据结构// 使用CopyOnWriteArrayList保证读写线程安全privatefinalListRunnableshutdownHooksnewCopyOnWriteArrayList();3. 幂等性设计// 防止重复执行关闭操作privatevolatilebooleanisShuttingDownfalse;4. 异常隔离机制// 单个关闭操作的异常不应影响其他操作try{hook.run();}catch(Exceptione){log.error(Error executing shutdown hook,e);// 继续执行下一个hook}实现步骤与代码第一步核心关闭管理器实现packagecom.dtstack.knowledge.ai.server.manager;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;importjava.util.concurrent.CopyOnWriteArrayList;importjava.util.List;/** * 统一关闭管理器 * * p该管理器负责在JVM关闭时执行所有注册的关闭操作确保资源被正确释放。 * 支持按key管理关闭操作提供注册和取消注册功能。/p * author changlu * since 2025-10-24 * * 示范用例 // 注册 ShutdownManager.getInstance().registerShutdownHook(key, () - { try { ... } catch (Exception e) { log.error(Error executing shutdown hook for DingTalk client, aid: {}, aid, e); } }); // 解绑 ShutdownManager.getInstance().unregisterShutdownHook(key); * */publicclassShutdownManager{privatestaticfinalLoggerlogLoggerFactory.getLogger(ShutdownManager.class);/** * 单例实例采用饿汉式实现确保线程安全 */privatestaticfinalShutdownManagerINSTANCEnewShutdownManager();/** * 关闭操作映射表使用ConcurrentHashMap保证线程安全 * key: 资源标识, value: 关闭操作 */privatefinalMapString,RunnableshutdownHookMapnewConcurrentHashMap();/** * 关闭状态标志volatile确保多线程环境下的可见性 */privatevolatilebooleanisShuttingDownfalse;/** * 私有构造函数注册JVM关闭钩子 */privateShutdownManager(){registerJvmShutdownHook();}/** * 注册JVM关闭钩子 */privatevoidregisterJvmShutdownHook(){Runtime.getRuntime().addShutdownHook(newThread(()-{log.info(JVM shutdown hook triggered, preparing to execute {} shutdown operations,shutdownHookMap.size());executeShutdown();}));log.debug(JVM shutdown hook registered successfully);}/** * 获取单例实例 * * return ShutdownManager单例实例 */publicstaticShutdownManagergetInstance(){returnINSTANCE;}/** * 注册关闭操作 * * p使用指定的key注册关闭操作相同的key会覆盖之前的操作/p * * param key 资源唯一标识 * param closeAction 关闭操作 */publicvoidregisterShutdownHook(Stringkey,RunnablecloseAction){if(isShuttingDown){log.warn(Shutdown process has started, new registration will be ignored, key: {},key);return;}if(keynull||key.trim().isEmpty()){log.warn(Attempt to register shutdown hook with null or empty key, operation ignored);return;}if(closeActionnull){log.warn(Attempt to register null shutdown hook for key: {}, operation ignored,key);return;}shutdownHookMap.put(key,closeAction);log.debug(Shutdown hook registered successfully, key: {}, current total: {},key,shutdownHookMap.size());}/** * 取消注册关闭操作 * * p移除指定key对应的关闭操作适用于资源主动释放的场景/p * * param key 要移除的资源标识 * return 如果成功移除返回true如果key不存在返回false */publicbooleanunregisterShutdownHook(Stringkey){if(keynull){log.warn(Attempt to unregister shutdown hook with null key);returnfalse;}RunnableremovedshutdownHookMap.remove(key);if(removed!null){log.debug(Shutdown hook unregistered successfully, key: {}, current total: {},key,shutdownHookMap.size());returntrue;}else{log.debug(Shutdown hook not found for unregister, key: {},key);returnfalse;}}/** * 检查指定key的关闭操作是否已注册 * * param key 资源标识 * return 如果已注册返回true否则返回false */publicbooleanisRegistered(Stringkey){returnshutdownHookMap.containsKey(key);}/** * 执行所有关闭操作 */publicvoidexecuteShutdown(){// 双重检查锁定防止重复执行if(isShuttingDown){return;}synchronized(this){if(isShuttingDown){return;}isShuttingDowntrue;}log.info(Starting shutdown process, total operations to execute: {},shutdownHookMap.size());longstartTimeSystem.currentTimeMillis();intsuccessCount0;intfailureCount0;// 顺序执行所有关闭操作for(Map.EntryString,Runnableentry:shutdownHookMap.entrySet()){Stringkeyentry.getKey();Runnablehookentry.getValue();try{log.debug(Executing shutdown hook for key: {},key);hook.run();successCount;log.debug(Shutdown hook executed successfully, key: {},key);}catch(Exceptione){failureCount;log.error(Error executing shutdown hook, key: {},key,e);}}// 清空已执行的关闭操作shutdownHookMap.clear();longdurationSystem.currentTimeMillis()-startTime;log.info(Shutdown process completed in {}ms, success: {}, failure: {},duration,successCount,failureCount);}/** * 手动触发关闭流程 */publicvoidshutdown(){log.info(Manual shutdown triggered);executeShutdown();}/** * 获取当前注册的关闭操作数量 */publicintgetHookCount(){returnshutdownHookMap.size();}/** * 检查是否正在关闭过程中 */publicbooleanisShuttingDown(){returnisShuttingDown;}/** * 获取所有已注册的key * * return 已注册的key集合 */publicjava.util.SetStringgetRegisteredKeys(){returnjava.util.Collections.unmodifiableSet(shutdownHookMap.keySet());}}第二步集成到钉钉客户端管理器注册关闭publicstaticvoidbindDingdingBot(Stringaid,DingdingBotConfigdingdingBotConfig,AiMessageProcessoraiMessageProcessor){...// 创建钉钉流式客户端OpenDingTalkClientopenDingTalkClientOpenDingTalkStreamClientBuilder.custom().credential(newAuthClientCredential(appKey,appSecret)).registerCallbackListener(DingTalkStreamTopics.BOT_MESSAGE_TOPIC,newChatBotCallbackListener(newRobotPrivateMessageService(accessTokenService,robotCode,appKey,appSecret),aiMessageProcessor)).build();try{// 启动客户端连接openDingTalkClient.start();openDingdingClientMap.put(aid,openDingTalkClient);// 注册关闭钩子registerShutdownHook(aid);log.info(DingTalk bot bound successfully, aid: {}, current client count: {},aid,openDingdingClientMap.size());}catch(Exceptione){log.error(Failed to bind DingTalk bot, aid: {}, appKey: {},aid,appKey,e);thrownewRuntimeException(Bind DingTalk bot failed,e);}}/** * 注册关闭钩子 * param aid 应用标识 */privatevoidregisterShutdownHook(Stringaid){ShutdownManager.getInstance().registerShutdownHook(aid,()-{try{log.info(Executing shutdown hook for DingTalk client, aid: {},aid);booleansuccessOpenDingTalkClientManager.closeClient(aid);if(success){log.info(DingTalk client closed successfully in shutdown hook, aid: {},aid);}else{log.warn(DingTalk client not found or already closed, aid: {},aid);}}catch(Exceptione){log.error(Error executing shutdown hook for DingTalk client, aid: {},aid,e);}});log.debug(Shutdown hook registered for DingTalk client, aid: {},aid);}/** * 取消注册关闭钩子 * param aid 应用标识 */privatevoidunregisterShutdownHook(Stringaid){booleanunregisteredShutdownManager.getInstance().unregisterShutdownHook(aid);if(unregistered){log.debug(Shutdown hook unregistered successfully, aid: {},aid);}else{log.debug(Shutdown hook not found for unregister, aid: {},aid);}}总结说明该方案的核心在于将资源管理的责任从分散的业务代码中集中到统一的管理器中通过JVM Shutdown Hook机制为各种异常退出场景提供了安全网。在实际生产环境中有效避免了连接泄漏和资源浪费提升了系统的整体稳定性和可维护性。资料获取大家点赞、收藏、关注、评论啦~精彩专栏推荐订阅在下方专栏长路-文章目录汇总算法、后端Java、前端、运维技术导航博主所有博客导航索引汇总开源项目Studio-Vue—校园工作室管理系统(含前后台SpringBootVue)博主个人独立项目包含详细部署上线视频已开源学习与生活-专栏可以了解博主的学习历程算法专栏算法收录更多博客与资料可查看获取联系方式文末获取开发资源及更多资源博客获取