CppMicroServices 微服务机制实现原理

基于 Modules/CppMicroServices/core/src/ 源码逐层分析


一、定位与基础思想

CppMicroServices 是 C++ 版的 OSGi 微服务规范实现(Apache License 2.0,独立开源项目)。
核心思想:

模块 A 注册一个接口的实现 → 模块 B 只凭接口类型查询 → 双方零编译依赖

与 CTK 插件框架完全无关——core/ 目录下没有任何 #include <ctk...> 引用,
可在纯命令行程序中独立运行。


二、核心数据结构:CoreModuleContext

所有状态集中在一个全局单例 CoreModuleContextusCoreModuleContext_p.h):

class CoreModuleContext {
public:
  ServiceListeners listeners;   // 所有服务事件监听器
  ServiceRegistry  services;    // 所有已注册服务
  ServiceHooks     serviceHooks; // 服务钩子(过滤/拦截)
  ModuleHooks      moduleHooks;  // 模块钩子
};

ModuleRegistry::coreModuleContext() 是进程级静态单例(US_GLOBAL_STATIC),
所有模块共享同一个 CoreModuleContext——这是"框架范围"服务可见性的基础。


三、模块生命周期:从 .so 加载到服务注册

1. 自动注册宏(usModuleInitialization.h: L57

每个参与微服务的动态库在源文件末尾放一行:

US_INITIALIZE_MODULE   // 展开为一个文件作用域的静态对象

宏展开后生成一个 ModuleInitializer_XXX 类的静态实例,其构造函数在 .so 被 dlopen 时
由 C++ 运行时自动调用:

// 宏展开核心逻辑(usModuleInitialization.h: L57-120)
class ModuleInitializer_XXX {
public:
  ModuleInitializer_XXX() {
    // 1. 通过自身地址获取 .so 的磁盘路径
    moduleInfoPtr()->location = ModuleUtils::GetLibraryPath(moduleInfoSym);
    // 2. 向全局 ModuleRegistry 注册
    ModuleRegistry::Register(moduleInfo());
  }
  ~ModuleInitializer_XXX() {
    ModuleRegistry::UnRegister(moduleInfo());   // .so 卸载时自动注销
  }
};
static ModuleInitializer_XXX _InitializeModule_XXX;  // 文件作用域静态对象

关键:不需要任何显式调用——.so 加载即注册,卸载即注销。

2. ModuleRegistry::Register(usModuleRegistry.cpp: L75

// 全局模块表:name → Module*(US_UNORDERED_MAP_TYPE)
US_GLOBAL_STATIC_WITH_DELETER(ModuleMap, modules, ModuleDeleter)
US_GLOBAL_STATIC(Mutex, modulesLock)   // 保护 modules 表

void ModuleRegistry::Register(ModuleInfo* info)
{
  // 检查是否重载(同 location + name 的模块)
  // 若是新模块:new Module() → 分配自增 id → 插入 modules 表
  module->Init(coreModuleContext(), info);
  module->Start();   // 触发 Activator::Load
}

3. Module::Start(usModule.cpp: L119

void Module::Start()
{
  d->moduleContext = new ModuleContext(this->d);   // 创建该模块的上下文句柄

  // 通过符号查找 Activator 工厂函数(dlsym 等价)
  std::string activator_func = "_us_module_activator_instance_" + d->info.name;
  void* activatorHookSym = ModuleUtils::GetSymbol(d->info, activator_func.c_str());
  // ...
  d->moduleActivator = activatorHook();            // 获取 Activator 实例
  d->moduleActivator->Load(d->moduleContext);      // 回调 Activator::Load

  // 发出 LOADED 事件
  d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this));
}

US_EXPORT_MODULE_ACTIVATOR(MyActivator) 宏生成那个 C 符号函数,
使 ModuleUtils::GetSymbol 能找到它。

4. Activator::Load —— 服务注册的入口

// 典型 Activator(如 mitkDisplayActionEventBroadcast.cpp: L48)
class MyActivator : public ModuleActivator {
  void Load(ModuleContext* ctx) override {
    // 在这里注册服务
    ctx->RegisterService<IMyInterface>(new MyImpl(), props);
  }
  void Unload(ModuleContext* ctx) override { /* 服务自动注销 */ }
};

四、服务注册:ServiceRegistry

核心数据结构(usServiceRegistry_p.h: L63-80

class ServiceRegistry {
  mutable MutexType mutex;

  // 服务对象 → 它注册的接口名列表
  MapServiceClasses services;          // unordered_map<ServiceRegistration, vector<string>>

  // 接口名 → 按 ranking 排序的服务注册列表(最高 rank 在前)
  MapClassServices  classServices;     // unordered_map<string, vector<ServiceRegistration>>

  std::vector<ServiceRegistrationBase> serviceRegistrations;  // 全量列表
};

RegisterService 流程(usServiceRegistry.cpp: L87

ServiceRegistrationBase ServiceRegistry::RegisterService(
    ModulePrivate* module, const InterfaceMap& service, const ServiceProperties& properties)
{
  // 1. 检查是否 ServiceFactory(工厂模式,按需创建实例)
  bool isFactory = service.count("org.cppmicroservices.factory") > 0;

  // 2. 收集接口名列表(InterfaceMap 的 key)
  std::vector<std::string> classes;
  for (auto& i : service) classes.push_back(i.first);

  // 3. 创建 ServiceRegistration(含自增 SERVICE_ID、OBJECTCLASS、SERVICE_SCOPE)
  ServiceRegistrationBase res(module, service,
      CreateServiceProperties(properties, classes, isFactory, ...));

  // 4. 加锁写入两张表
  MutexLock lock(mutex);
  services.insert({res, classes});
  for (auto& cls : classes) {
    auto& s = classServices[cls];
    s.insert(lower_bound(s, res), res);   // 按 ranking 有序插入
  }

  // 5. 发出 REGISTERED 事件,通知所有匹配的监听器
  ServiceEvent registeredEvent(ServiceEvent::REGISTERED, res.GetReference(""));
  module->coreCtx->listeners.GetMatchingServiceListeners(registeredEvent, listeners);
  module->coreCtx->listeners.ServiceChanged(listeners, registeredEvent);

  return res;
}

五、服务查询:ModuleContext → ServiceRegistry

// ModuleContext::RegisterService(usModuleContext.cpp: L78)
ServiceRegistrationU ModuleContext::RegisterService(const InterfaceMap& service,
                                                    const ServiceProperties& properties)
{
  return d->module->coreCtx->services.RegisterService(d->module, service, properties);
}

// ModuleContext::GetServiceReference(usModuleContext.cpp: L98)
ServiceReferenceU ModuleContext::GetServiceReference(const std::string& clazz)
{
  return d->module->coreCtx->services.Get(d->module, clazz);
}

ServiceRegistry::GetusServiceRegistry.cpp: L167):

ServiceReferenceBase ServiceRegistry::Get(ModulePrivate* module, const std::string& clazz) const
{
  MutexLock lock(mutex);
  std::vector<ServiceReferenceBase> srs;
  Get_unlocked(clazz, "", module, srs);   // 按接口名查 classServices 表
  if (!srs.empty()) return srs.back();    // 返回 ranking 最高的(back = 最高 rank)
  return ServiceReferenceBase();          // 未找到返回空引用
}

支持 LDAP 过滤器usLDAPExpr.cpp):GetServiceReferences(clazz, "(key=value)") 可按属性过滤。


六、服务事件与监听:ServiceListeners

注册服务时自动触发 ServiceEvent::REGISTERED;注销时触发 ServiceEvent::UNREGISTERING

消费方可用 ServiceTrackerusServiceTracker.h: L231)自动跟踪:

// 典型用法(如 QmitkAbstractView 中的 DataStorage 服务跟踪)
ServiceTracker<IMyInterface> tracker(context);
tracker.Open();                          // 开始跟踪,自动处理 Add/Remove/Modify
IMyInterface* svc = tracker.GetService(); // 获取当前最高 rank 服务
tracker.Close();

ServiceTracker 内部实现了 ServiceTrackerCustomizer,三个回调:

  • AddingService:新服务出现时
  • ModifiedService:服务属性变更时
  • RemovedService:服务注销时

七、模块卸载:自动清理

Module::StopusModule.cpp: L173)→ ModulePrivate::RemoveModuleResourcesusModulePrivate.cpp: L118):

void ModulePrivate::RemoveModuleResources()
{
  coreCtx->listeners.RemoveAllListeners(moduleContext);  // 移除所有监听器

  // 注销该模块注册的所有服务
  std::vector<ServiceRegistrationBase> srs;
  coreCtx->services.GetRegisteredByModule(this, srs);
  for (auto& sr : srs) sr.Unregister();

  // 释放该模块使用的所有服务引用
  coreCtx->services.GetUsedByModule(q, srs);
  for (auto& sr : srs) sr.GetReference("").d->UngetService(q, false);
}

模块卸载时无需手动清理——框架自动注销该模块的全部服务和监听器。


八、完整流程时序图

消费模块ServiceListenersServiceRegistryModuleActivatorModuleModuleRegistry 全局表ModuleInitializer 静态对象操作系统 dlopen消费模块ServiceListenersServiceRegistryModuleActivatorModuleModuleRegistry 全局表ModuleInitializer 静态对象操作系统 dlopen查询服务.so 卸载.so 加载 C++静态初始化Register moduleInfonew Module InitStart 创建 ModuleContextGetSymbol activator_func dlsymactivatorHook 获取实例Load moduleContextRegisterService InterfaceMap properties写入 services 和 classServices 表 加锁ServiceChanged REGISTERED 事件通知 ServiceTracker AddingServiceGetServiceReference clazzclassServices 按接口名查找 返回最高 rankServiceReferenceGetService reference服务对象指针析构函数UnRegisterStopUnloadRemoveModuleResources 自动注销所有服务ServiceChanged UNREGISTERING 事件

九、设计要点小结

设计点实现方式
零编译依赖消费方只#include 接口头文件,不 #include 实现头文件
自动注册US_INITIALIZE_MODULE 宏生成静态对象,.so 加载即注册
全局单例上下文US_GLOBAL_STATIC(CoreModuleContext) 进程级唯一
服务按 ranking 排序classServiceslower_bound 有序插入,Get 返回 back()
线程安全ServiceRegistry::mutex(MutexLock)保护所有读写
事件驱动注册/注销自动触发ServiceEventServiceTracker 响应
自动清理模块卸载时RemoveModuleResources 自动注销服务和监听器
LDAP 过滤GetServiceReferences(clazz, filter) 支持属性表达式查询
ServiceFactory注册时检测org.cppmicroservices.factory key,支持按需创建实例
与 CTK 零关系core/ 目录无任何 CTK 头文件引用,可脱离插件框架独立运行

关键源码文件索引

功能文件(Modules/CppMicroServices/core/src/ 下)关键行
全局上下文module/usCoreModuleContext_p.h全文
自动注册宏../include/usModuleInitialization.hL57-120
模块注册表module/usModuleRegistry.cppL39-74(数据结构);L75(Register)
模块生命周期module/usModule.cppL119(Start);L173(Stop)
模块资源清理module/usModulePrivate.cppL118-146
模块上下文 APImodule/usModuleContext.cppL78(RegisterService);L98(GetServiceReference)
服务注册表结构service/usServiceRegistry_p.hL63-80
服务注册实现service/usServiceRegistry.cppL87(RegisterService);L167(Get)
LDAP 过滤器module/usLDAPExpr.cpp-
服务跟踪器../include/usServiceTracker.hL231

附录:CTK 也提供微服务机制 —— 两套服务框架对比

一、CTK 确实内置完整的微服务机制

CTK 是 OSGi 规范的完整 C++ 实现,服务机制是其插件框架的内置组成部分。
MITK 中的实际用法(源码实证):

注册服务ctkPluginContext::registerService):

// berryCTKPluginActivator.cpp:256
registryServiceReg = context->registerService<IExtensionRegistry>(registry);

// berryWorkbenchPlugin.cpp:418
context->registerService<berry::IQtStyleManager>(styleManager.data());

跟踪/消费服务ctkServiceTracker):

// QmitkAbstractView.cpp:36,146
#include <ctkServiceTracker.h>
ctkServiceTracker<mitk::IDataStorageService*> m_DataStorageServiceTracker;

二、CTK 服务 vs CppMicroServices 对比

维度CTK 服务(ctkPluginContext)CppMicroServices(us::)
所在层Plugins 层(BlueBerry/CTK 插件框架内)Modules 层(独立于插件框架)
生命周期绑定绑定到 CTK 插件的 Start/Stop绑定到动态库加载/卸载(静态初始化)
注册 APIcontext->registerService<T>(impl)context->RegisterService<T>(impl)
跟踪器ctkServiceTracker<T>us::ServiceTracker<T>
依赖关系需要 CTK 插件框架运行零外部依赖,命令行程序可用
MITK 中用途框架级服务(IExtensionRegistry、IDataStorageService、IQtStyleManager)算法级服务(IO 读写器、InteractionEventObserver、渲染服务)

三、是否可以统一为一套机制

技术上可行,但不建议——两套机制的存在是有意为之的分层设计。

方案一:全部换成 CTK 服务

代价

  • Modules 层必须引入 CTK 头文件,打破"算法层不依赖插件框架"的分层原则
  • CoreCmdApps(纯命令行工具)无法运行,因为没有 CTK 插件框架
  • 每个 Module 都要变成 CTK 插件(有 plugin.xml、有 Activator),构建复杂度大幅上升

结论:破坏 MITK 最核心的设计原则——算法可脱离 GUI 复用。

方案二:全部换成 CppMicroServices

代价

  • CTK 插件的生命周期(Start/Stop)与 us:: 模块的生命周期(dlopen/dlclose)不对齐——CTK 插件可以在 .so 已加载的情况下被 Stop,此时 us:: 服务仍然存在,造成状态不一致
  • IExtensionRegistryIDataStorageService 这类框架级服务需要在特定插件激活后才有意义,用 us:: 无法表达"插件级"的生命周期语义

结论:生命周期语义对不上,框架级服务会出现"服务存在但插件未激活"的问题。

正确结论:两套分工是最优设计

Modules 层  → us:: 服务
              理由:零依赖、命令行可用、生命周期 = .so 生命周期

Plugins 层  → CTK 服务
              理由:生命周期 = 插件 Start/Stop、框架级服务语义清晰

在 Plugins 层统一用 CTK 服务(因为 Plugins 层本来就依赖 CTK),
同时保留 Modules 层的 us:: 不动——这正是 MITK 现在的做法,已经是最优分工。

更多推荐