MITK 工程四大组结构分析

MITK 工程四大组结构分析

Applications / CppMicroServices / Modules / Plugins 的作用与关系

概述

MITK 工程在解决方案中分为四个组。先说明一点:在源码树中 CppMicroServices

实际位于 Modules/CppMicroServices/,但因为它是独立的第三方项目

(有自己的 LICENSE、README、CMake 体系),在 VS 解决方案里被单列为一个组。

数量 一句话定位
CppMicroServices 1 服务总线:C++ 版 OSGi 微服务框架(接口注册/发现)
Modules 77 引擎和零件:算法与控件动态库,可脱离工作台复用
Plugins 82 仪表盘:BlueBerry 工作台插件(View/Editor/Perspective)
Applications 2 点火钥匙:可执行程序壳,main() + 插件清单

一、CppMicroServices ------ 服务注册中枢(最底层)

位置:Modules/CppMicroServices/(core/module、core/service、core/util)

C++ 版的 OSGi 微服务框架(来自独立开源项目)。提供"接口注册/发现"机制:

模块 A 注册一个服务接口的实现,模块 B 只凭接口类型就能查到它,双方零编译依赖

cpp 复制代码
// Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp: L48 ------ 实际用法
m_ServiceRegistration = us::GetModuleContext()->RegisterService<InteractionEventObserver>(this, props);

MITK 内部大量能力靠它解耦:

  • IO 读写器(各文件格式的 Reader/Writer 以服务注册)
  • 渲染服务、交互事件观察者(InteractionEventObserver)
  • DataStorage 服务(IDataStorageService)

二、Modules ------ 算法与功能库(核心主体,77 个)

纯 C++ 动态库,每个用 mitk_create_module() 声明(见 Modules/Core/CMakeLists.txt)。

内部分层

例子 说明
基础核心 Core(DataStorage、BaseRenderer、RenderingManager、SliceNavigationController)、Log 一切的地基
算法领域 SegmentationDICOMIGTImageStatisticsContourModel 医学影像算法
Qt 控件 QtWidgets(QmitkRenderWindow、QmitkStdMultiWidget)、各 *UI 后缀模块 可复用 UI 控件,但不含工作台逻辑
应用支撑 AppUtil(mitkBaseApplication)、CoreCmdApps 启动器骨架 / 纯命令行工具

模块声明示例(Modules/Core/CMakeLists.txt)

cmake 复制代码
mitk_create_module(
  DEPENDS
    PUBLIC
      MitkLog
      CppMicroServices        # ← Module 依赖服务总线
  PACKAGE_DEPENDS
    PUBLIC
      Boost
      nlohmann_json
      ITK|IOImageBase+...
      VTK|FiltersTexture+...  # ← 第三方库按需引组件
)

关键特征

Module 不依赖 BlueBerry/Plugins ------可以脱离工作台在任何 Qt/命令行程序里单独使用

CoreCmdApps 就是纯命令行用法)。这是 MITK "算法可独立复用"的设计基石。


三、Plugins ------ 工作台功能插件(UI 组装层,82 个)

CTK/BlueBerry 插件,每个用 mitk_create_plugin() 声明,带 plugin.xml

(贡献 View/Editor/Perspective 扩展)。

两大类

前缀 角色 例子
org.blueberry.* BlueBerry 框架本身(Eclipse RCP 移植层) org.blueberry.ui.qt(Workbench、presentation 框架)、org.blueberry.core.runtime(ExtensionRegistry)
org.mitk.gui.qt.* MITK 功能界面 datamanagersegmentationmxnmultiwidgeteditorstdmultiwidgeteditor

插件声明示例(org.mitk.gui.qt.datamanager)

cmake 复制代码
# CMakeLists.txt ------ 编译期:链接 Module
mitk_create_plugin(
  EXPORT_DIRECTIVE MITK_QT_DATAMANAGER
  EXPORTED_INCLUDE_SUFFIXES src
  MODULE_DEPENDS MitkQtWidgetsExt)     # ← 依赖 Modules 层
cmake 复制代码
# manifest_headers.cmake ------ 运行期:插件间依赖
set(Plugin-Name "MITK Data Manager")
set(Require-Plugin org.mitk.gui.qt.application org.mitk.gui.qt.common)

角色

Plugin 是 Module 与工作台之间的"胶水":把 Module 里的控件/算法包装成

View/Editor 插入 Workbench。两套依赖声明各司其职:

  • MODULE_DEPENDS ------ 编译期链接哪些 Module 库
  • Require-Plugin ------ 运行期需要哪些其他插件先激活

四、Applications ------ 可执行程序(最顶层,仅 2 个)

Applications/AppList.cmake

cmake 复制代码
set(MITK_APPS
  Workbench^^MITK_BUILD_APP_Workbench^^MitkWorkbench   # 默认 ON
  FlowBench^^MITK_BUILD_APP_FlowBench^^MitkFlowBench   # 默认 OFF
)

main() 有多薄(Applications/Workbench/MitkWorkbench.cpp)

cpp 复制代码
int main(int argc, char **argv)
{
  mitk::BaseApplication app(argc, argv);   // 来自 Modules/AppUtil
  app.setSingleMode(true);
  app.setApplicationName("MITK Workbench");
  app.setOrganizationName("DKFZ");
  ...
  return app.run();                        // 其余全交给插件框架
}

真正内容全部由插件提供,App 只在 target_libraries.cmake 里声明装载哪些插件:

cmake 复制代码
# Applications/Workbench/target_libraries.cmake
set(target_libraries
  org_blueberry_ui_qt              # 工作台框架
  org_mitk_gui_qt_extapplication   # 扩展应用外壳(传递拉入其余插件)
)

CTK 的依赖图工具(DGraph,见 AppList.cmake 注释)会自动解析插件传递依赖,

把需要的全部插件启用。


五、依赖关系(严格单向,自下而上)

#mermaid-svg-zscSvVonNvMQqcoK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zscSvVonNvMQqcoK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zscSvVonNvMQqcoK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zscSvVonNvMQqcoK .error-icon{fill:#552222;}#mermaid-svg-zscSvVonNvMQqcoK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zscSvVonNvMQqcoK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zscSvVonNvMQqcoK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zscSvVonNvMQqcoK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zscSvVonNvMQqcoK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zscSvVonNvMQqcoK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zscSvVonNvMQqcoK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zscSvVonNvMQqcoK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zscSvVonNvMQqcoK .marker.cross{stroke:#333333;}#mermaid-svg-zscSvVonNvMQqcoK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zscSvVonNvMQqcoK p{margin:0;}#mermaid-svg-zscSvVonNvMQqcoK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zscSvVonNvMQqcoK .cluster-label text{fill:#333;}#mermaid-svg-zscSvVonNvMQqcoK .cluster-label span{color:#333;}#mermaid-svg-zscSvVonNvMQqcoK .cluster-label span p{background-color:transparent;}#mermaid-svg-zscSvVonNvMQqcoK .label text,#mermaid-svg-zscSvVonNvMQqcoK span{fill:#333;color:#333;}#mermaid-svg-zscSvVonNvMQqcoK .node rect,#mermaid-svg-zscSvVonNvMQqcoK .node circle,#mermaid-svg-zscSvVonNvMQqcoK .node ellipse,#mermaid-svg-zscSvVonNvMQqcoK .node polygon,#mermaid-svg-zscSvVonNvMQqcoK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zscSvVonNvMQqcoK .rough-node .label text,#mermaid-svg-zscSvVonNvMQqcoK .node .label text,#mermaid-svg-zscSvVonNvMQqcoK .image-shape .label,#mermaid-svg-zscSvVonNvMQqcoK .icon-shape .label{text-anchor:middle;}#mermaid-svg-zscSvVonNvMQqcoK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zscSvVonNvMQqcoK .rough-node .label,#mermaid-svg-zscSvVonNvMQqcoK .node .label,#mermaid-svg-zscSvVonNvMQqcoK .image-shape .label,#mermaid-svg-zscSvVonNvMQqcoK .icon-shape .label{text-align:center;}#mermaid-svg-zscSvVonNvMQqcoK .node.clickable{cursor:pointer;}#mermaid-svg-zscSvVonNvMQqcoK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zscSvVonNvMQqcoK .arrowheadPath{fill:#333333;}#mermaid-svg-zscSvVonNvMQqcoK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zscSvVonNvMQqcoK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zscSvVonNvMQqcoK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zscSvVonNvMQqcoK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zscSvVonNvMQqcoK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zscSvVonNvMQqcoK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zscSvVonNvMQqcoK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zscSvVonNvMQqcoK .cluster text{fill:#333;}#mermaid-svg-zscSvVonNvMQqcoK .cluster span{color:#333;}#mermaid-svg-zscSvVonNvMQqcoK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zscSvVonNvMQqcoK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zscSvVonNvMQqcoK rect.text{fill:none;stroke-width:0;}#mermaid-svg-zscSvVonNvMQqcoK .icon-shape,#mermaid-svg-zscSvVonNvMQqcoK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zscSvVonNvMQqcoK .icon-shape p,#mermaid-svg-zscSvVonNvMQqcoK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zscSvVonNvMQqcoK .icon-shape .label rect,#mermaid-svg-zscSvVonNvMQqcoK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zscSvVonNvMQqcoK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zscSvVonNvMQqcoK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zscSvVonNvMQqcoK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Applications 壳 ------ main + 插件清单
装载:运行期由 CTK 解析 plugin.xml
MODULE_DEPENDS 编译期链接
DEPENDS PUBLIC CppMicroServices
CppMicroServices 服务总线
接口注册 / 发现
Modules 算法与控件库 ------ 可独立复用
QtWidgets 与各 UI 模块 ------ Qt 控件层
Core ------ 数据 / 渲染 / 交互核心
Segmentation / DICOM / IGT ------ 算法层
Plugins 工作台功能 ------ View / Editor / Perspective
Require-Plugin 运行期依赖
org.blueberry.* 框架层
org.mitk.gui.qt.* 功能界面
MitkWorkbench = BaseApplication + 插件列表

规则

  1. 依赖只能向下 :App → Plugin → Module → CppMicroServices;
    反向不允许------Module 永远不知道 Plugin 的存在。
  2. 横向解耦靠两套机制
    • Module 之间:CppMicroServices 服务(编译期只依赖接口)
    • Plugin 之间:BlueBerry 扩展点(plugin.xml 声明,运行期装配)
  3. 分层收益
    • 算法(Modules)可以不带 GUI 复用到第三方程序
    • 界面(Plugins)可按需增删,不改一行核心代码
    • 换一个应用(Applications)只是换一份插件清单

小结

CppMicroServices 是总线,Modules 是引擎和零件,
Plugins 是装在工作台上的仪表盘,Applications 只是点火钥匙。

关键文件索引

内容 文件
应用清单 Applications/AppList.cmake
Workbench 入口 Applications/Workbench/MitkWorkbench.cpp
App 插件清单 Applications/Workbench/target_libraries.cmake
Module 声明宏示例 Modules/Core/CMakeLists.txtmitk_create_module
Plugin 声明宏示例 Plugins/org.mitk.gui.qt.datamanager/CMakeLists.txtmitk_create_plugin
Plugin 运行期依赖 Plugins/org.mitk.gui.qt.datamanager/manifest_headers.cmake
微服务框架 Modules/CppMicroServices/(core/module、core/service)
微服务用法示例 Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp: L48
相关推荐
beibeix20152 天前
MITK plugin.xml 读取解析的实现过程
mitk
beibeix20157 天前
深入解析 MITK/BlueBerry 编辑器:从菜单点击到 QTabBar 的完整架构与呈现链路
mitk