MITK中两种微服务的三层架构实现对比
两种微服务的三层架构实现对比按 OSGi 规范的三层架构模块层 / 生命周期层 / 服务层对比CppMicroServicesus::与 CTK PluginFramework 的实现细节。源码位置CppMicroServices:D:/MITK/Modules/CppMicroServices/core/src/CTK:D:/MITK-superbuild-2023.12/ep/src/CTK/Libs/PluginFramework/OSGi 规范定义三层模块层Module Layer打包与依赖、生命周期层Lifecycle Layer安装/启动/停止、服务层Service Layer注册/发现。两套实现对三层的完成度截然不同。一、模块层Module Layer——“模块是什么、依赖怎么声明”CppMicroServicesus::CTK模块单位普通动态库.dll/.so无特殊打包CTK 插件带 META-INF/MANIFEST.MF 的 Qt 插件元数据可选manifest.json版本、autoLoadDirMANIFEST.MF 强制Plugin-SymbolicName、Plugin-Version、Require-Plugin、Plugin-ActivationPolicyctkPluginConstants.h: L132-240依赖声明没有——模块间依赖靠链接器编译期解决Require-Plugin: com.acme.test; plugin-version[1.0,2.0)——带版本区间的运行期依赖L204-209依赖解析无解析过程checkRequirePlugin递归解析 Require 链 版本区间匹配资源系统编译进二进制的资源容器usModuleResourceContainer资源存SQLitePLUGIN_RESOURCES_TABLE身份注册ModuleRegistry: name → Module*自增 idctkPlugins: location(URL) → QSharedPointerctkPluginSQLite 持久化安装状态CTK 依赖解析实现ctkPluginFrameworkContext.cpp: L269-300voidctkPluginFrameworkContext::checkRequirePlugin(ctkPluginPrivate*plugin){QListIteratorctkRequirePlugin*i(plugin-require);// MANIFEST 里的 Require-Plugin 列表while(i.hasNext()){ctkRequirePlugin*pri.next();// 按名字 版本区间找候选插件QListctkPlugin*plplugins-getPlugins(pr-name,pr-pluginRange);for(...每个候选 p2...){if(tempResolved.contains(p2))okp2;// 正在本轮解析中处理循环依赖elseif(RESOLVED_FLAGSp2-state)okp2;// 已解析elseif(p2-statectkPlugin::INSTALLED)// 递归解析依赖的依赖tempResolved 集合防环...}}}核心差异us:: 的模块层是退化的——没有版本、没有依赖解析、没有安装概念模块 已被 OS 加载的库。CTK 实现了完整 OSGi 模块层——版本区间依赖、解析失败可诊断、安装状态跨进程持久SQLite。二、生命周期层Lifecycle Layer——“状态机与钩子”CTK完整六态状态机ctkPlugin.h: L87-103UNINSTALLED ← INSTALLED → RESOLVED → STARTING → ACTIVE ↑ │ └──── STOPPING ←─────┘INSTALLED→RESOLVEDgetUpdatedStatectkPlugin_p.cpp: L174-198触发依赖解析成功才置 RESOLVED 并广播事件——装了和能用是两个状态启动start0()ctkPlugin_p.cpp: L720-790ctkPluginException*ctkPluginPrivate::start0(){fwCtx-listeners.emitPluginChanged(ctkPluginEvent(STARTING,...));pluginLoader.load();// QPluginLoader 加载库pluginActivatorqobject_castctkPluginActivator*(pluginLoader.instance());// Qt 插件根对象即 ActivatorpluginActivator-start(pluginContext.data());// 回调 start()statectkPlugin::ACTIVE;...// 异常回滚路径L780-789// STOPPING → removePluginResources() → context invalidate → 退回 RESOLVED}每一步状态迁移都发 ctkPluginEventSTARTING/STARTED/STOPPING/STOPPED支持懒激活Plugin-ActivationPolicy: eager/lazystart 中途被 uninstall 有专门检测STATECHANGE_ERRORActivator 接口ctkPluginActivator.h: L71-111classctkPluginActivator{virtualvoidstart(ctkPluginContext*context)0;virtualvoidstop(ctkPluginContext*context)0;};CppMicroServices二态usModule.h: L64,166未加载 ⇄ 已加载IsLoaded() 一个 bool加载即注册即启动静态初始化US_INITIALIZE_MODULE→ModuleRegistry::Register→Module::Start一气呵成没有中间可停留的状态Activator 获取用原生符号查找usModule.cpp: L133-135std::string activator_func_us_module_activator_instance_d-info.name;void*symModuleUtils::GetSymbol(d-info,activator_func.c_str());// dlsym 等价d-moduleActivatoractivatorHook();d-moduleActivator-Load(d-moduleContext);事件只有 LOADING/LOADED/UNLOADING/UNLOADED 四种无 RESOLVED 概念无异常回滚状态机Activator::Load抛异常直接向上传播L152-156 注释明说语义上视为 noexcept核心差异CTK 的生命周期与 .so 加载解耦——库可以加载着但插件停在 RESOLVED 未激活BlueBerry ExtensionRegistry 正是利用这一点插件 RESOLVED 就解析它的 plugin.xml不必 start懒激活的基础。us:: 的生命周期与 .so 加载同一简单但无法表达就绪未启动。三、服务层Service Layer——“几乎是同一份代码”这一层两者都是 Knopflerfish 的完整移植结构逐字段对应机制CppMicroServicesCTK差异双表存储servicesclassServicesusServiceRegistry_p.h: L63-80同名双表ctkServices_p.h: L64-71仅容器STL vs QHashranking 排序lower_bound有序插入Get取back()同无服务本体InterfaceMap std::mapstring, void*QObject*QStringList接口名CTK 服务必须是 QObject用qobject_cast校验接口使用记账dependents: MapModule*,intdependents: QHashQSharedPointerctkPlugin,int同构作用域singleton / module / prototype 三种SERVICE_SCOPEsingleton ctkServiceFactoryus:: 多 prototype事件分发回调接口 监听器分桶objectclass/service.id 两级 cacheQt 信号槽ctkServiceSlotEntryreceiverslot 名事件投递机制不同LDAP 过滤usLDAPExprctkLDAPExpr同一算法自动清理RemoveModuleResources卸载时注销全部服务归还引用removePluginResources()stop 时同样操作同构跟踪器us::ServiceTracker.tpp 模板ctkServiceTracker同构核心差异只有两点CTK 服务绑定 Qt 元对象系统服务必须是 QObject、事件走信号槽、接口用Q_DECLARE_INTERFACEqobject_castus:: 零 Qt 依赖靠模板。锁粒度CTK 部分用 QReadWriteLockus:: 单 Mutex。总结一张表看三层完成度OSGi 层CppMicroServicesCTK模块层◐ 退化无版本/无依赖解析模块已加载的库● 完整MANIFEST Require-Plugin 版本区间 递归解析 SQLite 持久化生命周期层◐ 二态加载/未加载静态初始化自动走完● 完整六态状态机 事件 懒激活 异常回滚服务层● 完整Knopflerfish 移植● 完整同一份 Knopflerfish 移植Qt 化这解释了 MITK 的分工为什么合理Modules 层用 us::——算法库不需要安装/解析/延迟启动这些重量级语义加载即用、零依赖最合适Plugins 层用 CTK——UI 插件需要版本依赖、按需激活、RESOLVED 阶段读 plugin.xml非完整生命周期不可两者服务层同源同构所以开发者跨层切换时 API 心智模型几乎不变。关键源码文件索引CppMicroServicesModules/CppMicroServices/core/下层内容文件关键行模块层模块表src/module/usModuleRegistry.cppL39-73模块层manifest.json 解析src/module/usModulePrivate.cppL53-68生命周期层二态判定include/usModule.hL64, L166IsLoaded生命周期层Start/符号查找src/module/usModule.cppL119-171生命周期层自动注册宏include/usModuleInitialization.hL57-120服务层服务双表src/service/usServiceRegistry_p.hL63-80服务层注册私有体/dependentssrc/service/usServiceRegistrationBasePrivate.hL40-115服务层监听器分桶src/service/usServiceListeners_p.hL43-65CTKep/src/CTK/Libs/PluginFramework/下层内容文件关键行模块层MANIFEST 头常量ctkPluginConstants.hL132-240模块层Require-Plugin 解析ctkPluginFrameworkContext.cppL269-300checkRequirePlugin模块层插件表ctkPlugins_p.hL45-63模块层SQLite 存储ctkPluginStorageSQL.cppL38-39生命周期层六态状态机ctkPlugin.hL59-103生命周期层RESOLVED 判定ctkPlugin_p.cppL174-198getUpdatedState生命周期层start0/QPluginLoader/回滚ctkPlugin_p.cppL720-790生命周期层Activator 接口ctkPluginActivator.hL71-111服务层服务双表ctkServices_p.hL40-71服务层信号槽事件ctkServiceSlotEntry_p.hL45-75两种微服务的应用实例追踪本文是《两种微服务的三层架构实现对比》的补充各取一个真实 MITK 例子端到端描述具体实现过程。例一CppMicroServicesInteractionEventObserver交互事件观察者例二CTKIDataStorageService数据仓库服务例一 CppMicroServicesInteractionEventObserverus:: 微服务在 MITK 里最典型的应用鼠标交互事件如何广播给不认识的观察者十字光标同步链路中的DisplayActionEventBroadcast正是靠它接入的。① 定义接口Modules/CoreModules/Core/include/mitkInteractionEventObserver.hstructInteractionEventObserver{virtualvoidNotify(InteractionEvent*event,boolisHandled)0;...};只有头文件没有任何实现依赖——消费方和提供方都只 include 它。② 提供方注册服务构造时Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp: L46-48——对象构造时把自己注册进服务表mitk::DisplayActionEventBroadcast::DisplayActionEventBroadcast(){us::ServiceProperties props;props[name]std::string(DisplayActionEventBroadcast);// 以 InteractionEventObserver 接口注册自身m_ServiceRegistrationus::GetModuleContext()-RegisterServiceInteractionEventObserver(this,props);}内部发生的事RegisterService→ServiceRegistry::RegisterServiceusServiceRegistry.cpp: L87接口名us_service_interface_iidInteractionEventObserver()作为 key写入classServices表立即广播ServiceEvent::REGISTERED析构时m_ServiceRegistration.Unregister()自动注销③ 消费方用 ServiceTracker LDAP 过滤器查找Modules/Core/src/Interactions/mitkDispatcher.cpp: L40-49——每个渲染窗口的事件分发器构造时建跟踪器// 构造 LDAP 过滤器只要 InteractionEventObserver 这个接口的服务std::string classInteractionEventObserver(us::ServiceConstants::OBJECTCLASS()us_service_interface_iidInteractionEventObserver());// 再按属性过滤全局的 或 专属本 renderer 的us::LDAPFilterfilter(((|specificRendereranyRenderer)classInteractionEventObserver));m_EventObserverTrackernewus::ServiceTrackerInteractionEventObserver(us::GetModuleContext(),filter);LDAP 过滤器的实战用法不只按接口还按props里的属性筛选——同一接口的多个服务实例可以按属性精确圈定。④ 每次事件分发时动态取服务mitkDispatcher.cpp: L198-213——每处理一个鼠标/键盘事件/* Notify InteractionEventObserver */conststd::vectorus::ServiceReferenceInteractionEventObserverlistEventObserverm_EventObserverTracker-GetServiceReferences();// 拿当前时刻的全部匹配服务for(autoit:listEventObserver){InteractionEventObserver*observerm_EventObserverTracker-GetService(it);if(observerobserver-IsEnabled())observer-Notify(event,eventIsHandled);// 广播}每次都现查——运行中途新加载一个带观察者的模块比如测量工具模块注册了自己的观察者下一个鼠标事件就会自动广播给它Dispatcher 一行代码不用改。完整链路DisplayActionEventBroadcast 构造 → RegisterServiceInteractionEventObserver(this) [提供方Modules/Core] → classServices[...InteractionEventObserver] 本实例 ↓ 运行期解耦 QmitkRenderWindow 收到鼠标事件 → Dispatcher::ProcessEvent → ServiceTracker(LDAP过滤).GetServiceReferences() [消费方互不 include 实现] → observer-Notify(event) → SetCrosshair/Scroll/... → 十字光标同步链路例二 CTKIDataStorageServiceCTK 服务在 MITK 里最核心的应用所有 View 如何拿到全局唯一的 DataStorage。① 定义接口带 Qt 元对象声明Plugins/org.mitk.core.services/src/mitkIDataStorageService.h: L29-49structMITK_CORE_SERVICES_PLUGINIDataStorageService{virtualIDataStorageReference::PointerGetDataStorage()const0;virtualIDataStorageReference::PointerGetDefaultDataStorage()const0;...};// CTK 服务必须做 Qt 接口声明——这是与 us:: 的关键差异Q_DECLARE_INTERFACE(mitk::IDataStorageService,org.mitk.service.IDataStorageService)② 提供方在插件 Activator::start 里注册Plugins/org.mitk.core.services/src/internal/mitkPluginActivator.cpp: L90-91——org.mitk.core.services插件被 CTK启动进入 ACTIVE 状态时voidorg_mitk_core_services_Activator::start(ctkPluginContext*context){dataStorageService.reset(newDataStorageService());// 创建实现context-registerServicemitk::IDataStorageService(dataStorageService.data());}对比例一us:: 的注册发生在对象构造/模块加载时CTK 的注册发生在插件 start时——三层对比文档里生命周期绑定点不同在真实代码中的体现。CTK 内部用qobject_cast校验实现确实携带Q_DECLARE_INTERFACE声明的接口然后写入ctkServices的双表。③ 消费方用 ctkServiceTrackerPlugins/org.mitk.gui.qt.common/src/QmitkAbstractView.cpp// L146: 私有类成员——跟踪器ctkServiceTrackermitk::IDataStorageService*m_DataStorageServiceTracker;// L51-57: 构造时打开跟踪QmitkAbstractViewPrivate(QmitkAbstractView*qq):m_DataStorageServiceTracker(QmitkCommonActivator::GetContext())// 插件上下文{m_DataStorageServiceTracker.open();// 开始跟踪服务出现/消失自动感知}// L390-400: 任何 View 调 GetDataStorage() 时mitk::DataStorage::PointerQmitkAbstractView::GetDataStorage()const{mitk::IDataStorageService*dsServiced-m_DataStorageServiceTracker.getService();if(dsService!nullptr)returndsService-GetDataStorage()-GetDataStorage();returnnullptr;}④ 自动清理View 析构 →m_DataStorageServiceTracker.close()→ 停止跟踪插件 stop →removePluginResources()→ 注销服务 清理依赖计数服务注销时所有持有引用的 View 自动收到serviceRemoved信号getService()返回 nullptr完整链路org.mitk.core.services 插件启动ACTIVE → Activator::start() → registerServiceIDataStorageService(dataStorageService) [提供方] → ctkServices[org.mitk.service.IDataStorageService] 本实例 ↓ 运行期解耦 QmitkAbstractView 构造 → ctkServiceTracker.open() → 监听服务注册/注销信号 → 任何 View 调 GetDataStorage() → tracker.getService() → DataStorageService::GetDataStorage() → 全局唯一 DataStorage 实例对比小结维度CppMicroServicesInteractionEventObserverCTKIDataStorageService注册时机对象构造时模块加载即注册插件 start 时ACTIVE 状态才注册接口声明纯 C 结构体模板元编程Q_DECLARE_INTERFACE Qt 元对象服务发现ServiceTrackerLDAPFilter属性过滤ctkServiceTrackerQt 信号槽监听生命周期绑定与模块加载/卸载同步与插件状态机INSTALLED→RESOLVED→ACTIVE同步典型场景跨模块事件广播鼠标交互插件间共享单例全局 DataStorage这两个实例完整展示了三层架构对比在 MITK 中的实际应用us:: 用于模块层的轻量事件广播CTK 用于插件层的完整生命周期管理 服务共享。

相关新闻

深度解析CodableWrappers架构:从零构建自己的属性包装器编码器

深度解析CodableWrappers架构:从零构建自己的属性包装器编码器

深度解析CodableWrappers架构:从零构建自己的属性包装器编码器 【免费下载链接】CodableWrappers A Collection of PropertyWrappers to make custom Serialization of Swift Codable Types easy 项目地址: https://gitcode.com/gh_mirrors/co/CodableWrappers …

2026/7/27 20:09:26 阅读更多 →
从世界状态到可执行控制:Cosmos 3 Edge 与机器人控制器之间应建立什么合同

从世界状态到可执行控制:Cosmos 3 Edge 与机器人控制器之间应建立什么合同

从世界状态到可执行控制:Cosmos 3 Edge 与机器人控制器之间应建立什么合同 TL;DR 场景:Cosmos 3 Edge 把视觉理解、未来预测、视频生成和动作生成放入同一套 4B 世界表示,端侧机器人需要把"模型提案"和"硬件执行"清晰分…

2026/7/27 20:09:26 阅读更多 →
地质灾害监测预警数据集解析与应用实践

地质灾害监测预警数据集解析与应用实践

1. 地质灾害监测预警数据集的行业价值作为一名长期从事地质灾害监测算法开发的工程师,我深知高质量数据对于模型训练的重要性。在边坡形变分析和地质灾害预警领域,最大的痛点莫过于缺乏带精确空间坐标和时序轨迹的真实监控数据。传统的数据采集方式往往存…

2026/7/27 20:09:26 阅读更多 →

最新新闻

2025年最佳网盘直链下载助手:一键解锁九大网盘高速下载

2025年最佳网盘直链下载助手:一键解锁九大网盘高速下载

2025年最佳网盘直链下载助手:一键解锁九大网盘高速下载 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

2026/7/27 20:16:27 阅读更多 →
AES加密技术原理与在线教育平台安全实践

AES加密技术原理与在线教育平台安全实践

1. AES加密技术基础解析 AES(Advanced Encryption Standard)作为当今最广泛使用的对称加密算法,其核心价值在于平衡了安全性与性能。2001年由NIST正式确立为标准,取代了原有的DES算法。AES采用分组加密机制,固定处理12…

2026/7/27 20:16:27 阅读更多 →
CTF实战:从爱情故事中破解AES-CBC加密的Python脚本详解

CTF实战:从爱情故事中破解AES-CBC加密的Python脚本详解

1. 项目概述:一次别开生面的CTF实战复盘最近在CTFshow平台的一场水友赛中,遇到了一道非常有意思的题目。它没有直接给你一个冷冰冰的加密文件或一串十六进制密文,而是将一道AES加密的挑战,巧妙地包装在一个“爱情故事”的叙事里。…

2026/7/27 20:16:27 阅读更多 →
LM3S1968定时器与看门狗寄存器级配置实战指南

LM3S1968定时器与看门狗寄存器级配置实战指南

1. 项目概述与核心价值在嵌入式开发领域,尤其是基于ARM Cortex-M内核的微控制器应用,定时器和看门狗是两个你绕不开的核心外设。它们一个负责精准的“心跳”和“节拍”,另一个则扮演着系统“守护神”的角色。今天,我们就来深入聊聊…

2026/7/27 20:16:27 阅读更多 →
IDEA算法与位平面分解的图像加密技术详解

IDEA算法与位平面分解的图像加密技术详解

1. 项目背景与核心思路在数字图像安全传输领域,位平面加密技术因其独特的细粒度控制能力而备受关注。这个方案将国际数据加密算法(IDEA)与图像位平面分解技术相结合,实现了像素级的安全防护。不同于传统的整体加密方式&#xff0c…

2026/7/27 20:16:27 阅读更多 →
30分钟学会Vue插值操作:VueLearnNotes中的Mustache语法与指令详解

30分钟学会Vue插值操作:VueLearnNotes中的Mustache语法与指令详解

30分钟学会Vue插值操作:VueLearnNotes中的Mustache语法与指令详解 【免费下载链接】VueLearnNotes Vue学习笔记 项目地址: https://gitcode.com/gh_mirrors/vu/VueLearnNotes Vue插值操作是前端开发中实现数据动态渲染的核心技术,通过简洁的语法可…

2026/7/27 20:15:27 阅读更多 →

日新闻

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →
SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

1. 项目概述:从寄存器手册到实战指南 如果你手头有一份类似德州仪器(TI)TMS320x240xA系列DSP的SPI模块技术手册,看着里面密密麻麻的寄存器位定义、时序图和公式,是不是感觉头大?这份资料虽然权威&#xff0…

2026/7/27 0:00:54 阅读更多 →
【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/27 4:33:59 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/27 6:31:56 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/27 4:01:12 阅读更多 →

月新闻