OSGI for C++——通往架构师之路

课程介绍

OSGI 技术是面向 Java 的动态模型系统。Java 圈子里有非常著名的一句话:OSGI——架构师的天堂。换句话说,OSGI 能让软件开发变得更加容易!

值得庆幸的是,在 C++ 中也有类似的框架——CTK Plugin Framework。它借鉴了 OSGI 的思想,并实现了几乎完整的 OSGI 框架 API!

在通往架构师的道路上,不仅需要了解面向组件(或服务)的设计和实现,更应当了解其背后的原理。本达人课,我们将主要围绕 CTK,探索 C++ 中的模块化技术。希望通过分享的知识,大家能够了解 OSGI 内部的工作机制,并能够基于 CTK 快速搭建 C++ 组件化框架。

本达人课共包含四大部分:

  • 第一部分(第 01-03 课):入门篇,初步了解,包括框架选择标准、OSGI 和 CTK 之间的关系、CTK 的优势解析及基础初探。

  • 第二部分(第 04-10 课):进阶篇,开始使用,包括开发环境的搭建,CTK 的编译、插件的创建,以及如何在程序中嵌入插件框架等功能。

  • 第三部分(第 11-17 课):高级篇,掌握核心,CTK 事件管理机制、日志管理、服务追踪、事件与监听等功能。

  • 第四部分(第 18 课):总结篇 ,FAQ 常见问题,针对 CTK 中的常见问题进行快速分析,并给出最合理的解决方案。

作者简介

王亮,现就职于某上市公司,担任高级工程师、架构师,CSDN 博客专家(昵称:一去丶二三里),从事 C++、Python 开发工作,专注于代码,热衷于分享。

课程内容

第01课:入门篇——初识 CTK

CTK 是什么

CTK 为支持生物医学图像计算的公共开发包,其全称为 Common Toolkit。

CTK 标志

Logo 是一个品牌的形象,对外它传递的是一种精神和理念,所以绝大多数组织都有着与自己相符的标志。Apple 的标志是一个被咬了一口的苹果,Microsoft 的标志是一面窗户(至少最初是),而 CTK 的标志是:

image

第一印象,你是否和我一样,觉得它不够时尚,甚至很丑。

但若仔细看,你会发现这个设计很有意思,像一群人环绕着“CTK”三个字母,举着双臂对着它欢呼。简洁、巧妙,在图形上给予了 CTK 最鲜活的注解,疯狂打 Call 吧!

CTK 的诞生

在 2009 年 6 月,由 MBI 在海德堡(德国)的 DKFZ 主办了一场关于 CTK 的研讨会,会议的目的有两个:

  • 召集一些利用 BSD 风格许可、且从事 FOSS(Free Open Source Software)医学图像计算平台开发的团队;
  • 探讨有意义的协调和整合的方式。

会议的第一天是介绍软件(模块化的体系结构),第二天是头脑风暴和概念开发(许可 - BSD 风格、语言 - C++)。

在首次筹备会议之后,2009 年 9 月 25 日,代表医学成像和建模领域的研究在牛津(英国)举行了跟进会议,将 CTK 定位为“迅速成为全球生物医学可视化和计算领域最重要的软件资源”。这项倡议背后的基本思想是停止重新发明轮子,并驻力于那些构成每个生物医学软件包基础的方面,使研究人员能够专注于那些构成真正创新的特定功能。这次会议的目的也有两个:

  • 为 CTK 的未来建立了一些基本规则。例如,将其作为一个免费的开源软件(FOSS)在 BSD 许可下发布。
  • 建立一个 CTK 临时指导委员会(由参加牛津会议的组织代表组成),负责监督定义范围的初始阶段和工具包的总体架构。

此后,经过了大约一年的时间,CTK 推出了一个全面的、完整的开源项目,任何人都可以参与其中。

CTK 提供了什么

当前,CTK 工作的主要范围包括:

  • DICOM:提供了从 PACS 和本地数据库中查询和检索的高级类。包含 Qt 部件,可以轻松地设置服务器连接,并发送查询和查看结果。
  • DICOM Application Hosting:目标是创建 DICOM Part 19 Application Hosting specifications 的 C++ 参考实现。它提供了用于创建主机和托管应用程序的基础设。
  • Widgets:用于生物医学成像应用的 Qt Widgets 集合。
  • Plugin Framework:用于 C++ 的动态组件系统,以 OSGi 规范为模型。它支持一个开发模型,在这个模型中,应用程序(动态地)由许多不同(可重用的)组件组成,遵循面向服务的方法。
  • Command Line Interfaces:一种允许将算法编写为自包含可执行程序的技术,可以在多个终端用户应用程序环境中使用,而无需修改。

CTK 的目标

如果说老王的小目标是先挣它一个亿,那么 CTK 的目标要比他小很多:

  • 为医学成像提供一组统一的基本功能;
  • 促进代码和数据的交互及结合;
  • 避免重复开发;
  • 在工具包(医学成像)范围内不断扩展到新任务,而不会增加现有任务的负担;
  • 整合并适应成功的解决方案。

CTK 基于哪些技术

在 CTK 整个开发过程中,它使用了一些非常棒的技术。

  • BSD 许可

CTK 采用 BSD 形式的许可,对用户不做任何限制并允许商业使用。因此,所贡献和使用的库也都具有兼容的许可证。

  • C++

CTK 的主要语言是 C++。

CTK 的所有代码均托管于 Github。

Qt 被用作 CTK 中的 GUI 工具包,以及诸如跨平台数据库访问的非 GUI 任务。

CMake 被用作构建自动化工具以及 Package 系统。

另外,DICOM 支持并使用 DCMTK、可视化使用 VTK、分析算法使用 ITK

注意: CTK 的代码是在 Apache 2.0 下授权的。这意味着,可以使用 CTK 代码进行学术、商业或其他目的,而无需支付许可费。

第02课:入门篇——漫谈 CTK

十万个为什么

五千个在哪里?七千个怎么办?十万个为什么?……生活中,有很多奥秘在等着我们去思考、揭示!

同样地,在使用 CTK 时,很多小伙伴一定也存在诸多疑问:

  • 为什么 CTK Plugin Framework 要借鉴 OSGi?
  • 为什么 CTK 要基于 Qt 实现?
  • CTK Plugin Framework 的架构策略是什么?
  • 使用 CTK Plugin Framework 的好处是什么?
  • 为什么 CTK 不流行?

针对这些问题,我们来一探究竟!

为什么 CTK Plugin Framework 要借鉴 OSGi?

对于任何新框架/库,在设计之初都需要考虑众多因素,CTK Plugin Framework 也不例外:

  • 框架不得对插件强加功能限制;
  • 插件应该通过定义良好的方式(服务、接口等)进行通信;
  • 必须处理插件之间的依赖关系;
  • 应该在运行时加载插件;
  • ……

看似每一项任务都极具挑战,该如何应对呢?调研!!!这应该是每一个技术人首先想到的,因为它是最快、最直接的办法,仔细研究已有方案是非常有益的。就这样,CTK 小组研究了一系列面向服务的设计,其中比较出名的有:

  • CORBA:由 OMG 组织制订的一种标准的面向对象应用程序体系规范;
  • OSGi:Java 动态化模块化系统的一系列规范;
  • ……

一开始,CORBA 看起来挺有意思,但是对 CTK 的目标用户来说,会带来太多的开销并增加很多复杂性。此外,也有一些其他解决方案也能够很好地处理可扩展性,但是它们通常需要实现一些特殊的接口,这在一般情况下不太合适。

OSGi 规范的核心部分是一个框架,其中定义了应用程序的生命周期模式和服务注册。基于这个框架定义了大量的 OSGi 服务:日志、配置管理、偏好,HTTP(运行 servlet)、XML 分析、设备访问、软件包管理、许可管理、星级、用户管理、IO 连接、连线管理、Jini 和 UPnP。由于 OSGi 的可靠性和可扩展性,很多大规模和分布式应用程序都基于它来构建,例如:IDE(Eclipse)、应用服务器(GlassFish、IBM Websphere、Oracle/BEA Weblogic、Jonas、JBoss)、应用框架(Spring、Guice)等。

因此,在某种程度上,像 OSGi 这样的通用插件框架最适合作为 CTK Plugin Framework 的指导方案。能从 OSGi 社区获得的 10 多年经验中受益,谁能不心动呢?

PS: 对于 OSGi 开发人员来说,理解 CTK Plugin Framework 的 API 相对容易。

为什么 CTK 要基于 Qt 实现?

在使用 CTK 时,总能听到质疑的声音:“如果不用 Qt,CTK 一定会很火!”

毛主席曾说:没有调查,没有发言权!

无需过多争论,用事实说话!看看究竟是什么原因,才使得 CTK 基于 Qt 来实现?

  • CTK 需要为生物医学成像应用提供一系列 Widgets。

在 CTK 设计之初,它的目标之一就是为所在领域提供一系列控件。在 C++ 中要找一个高效、跨平台的 GUI 库,我想没有比 Qt 更合适的!

  • Qt Creator 的可扩展性。

Qt Creator 通过一种简单、优雅的方式来实现可扩展性,它使用一个通用的 QObject 池来实现某些可用的接口。同时,通过使用嵌入式文本文件(.pluginspec 文件)来向插件添加元数据(例如:Name、Version 等)。

其实严格来说,CTK Plugin Framework 同时借鉴了 OSGi 和 Qt Creator 的思想。

  • Qt 提供了 Qt Plugin System 和 Qt Service Framework。

Qt Plugin System 提供了两套用于创建插件的 API,高级 API 用于扩展 Qt 本身(例如:自定义数据库驱动、图像格式、文本编解码、自定义样式等),低级 API 用于扩展 Qt 应用程序。

对于 Qt Service Framework 来说,它能使服务的开发和访问方式变得更加容易。Qt 服务提供者可以与特定于平台的服务进行交互,而无需向客户端公开平台的细节。每个服务都通过 QObject 指针公开,这意味着客户端可以通过 Qt MetaObject 系统与服务对象进行交互。

CTK Plugin Framework 的架构策略是什么?

CTK Plugin Framework 是基于 Qt Plugin System 和 Qt Service Framework 实现的,并且它还添加了以下特性来增强这两个系统:

  • 插件元数据(由 MANIFEST.MF 文件提供);
  • 一个定义良好的插件生命周期和上下文;
  • 综合服务发现和注册;
  • ……

注意: 在 Qt Plugin System 中,插件的元数据由 JSON 文件提供。

CTK Plugin Framework 的核心架构主要包含两个组件:Plugin System 本身和 Service Registry。然而,这两个组件是相互关联的,它们在 API 级别上的组合使得系统更加全面、灵活。

  • Plugin System

CTK Core 依赖于 QtCore 模块,因此 CTK Plugin Framework 基于 Qt Plugin System。Qt API 允许在运行时加载和卸载插件,这个功能在 CTK Plugin Framework 中得到了加强,以支持透明化延迟加载和解决依赖关系。

插件的元数据被编译进插件内部,可以通过 API 进行提取。此外,插件系统还使用 SQLite 缓存了元数据,以避免应用程序加载时间问题。另外,Plugin System 支持通过中央注册中心使用服务。

  • Service Registry

Qt Service Framework 是 Qt Mobility 项目发布的一个 Qt 解决方案,这种服务框架允许“声明式服务”(Getting Started with OSGi: Introducing Declarative Services )和按需加载服务实现。为了启用动态(非持久性)服务,Qt Mobility 服务框架可以与 Service Registry 一起使用,类似于 OSGi Core Specifications 中描述的一样。

使用 CTK Plugin Framework 的好处是什么?

由于 CTK Plugin Framework 基于 OSGi,因此它继承了一种非常成熟且完全设计的组件系统,这在 Java 中用于构建高度复杂的应用程序,它将这些好处带给了本地(基于 Qt 的)C++ 应用程序。以下内容摘自 Benefits of Using OSGi,并适应于 CTK Plugin Framework:

  • 降低复杂性

使用 CTK Plugin Framework 开发意味着开发插件,它们隐藏了内部实现,并通过定义良好的服务来和其它插件通信。隐藏内部机制意味着以后可以自由地更改实现,这不仅有助于 Bug 数量的减少,还使得插件的开发变得更加简单,因为只需要实现已经定义好的一定数量的功能接口即可。

  • 复用

标准化的组件模型,使得在应用程序中使用第三方组件变得非常容易。

  • 现实情况

CTK Plugin Framework 是一个动态框架,它可以动态地更新插件和服务。在现实世界中,有很多场景都和动态服务模型相匹配。因此,应用程序可以在其所属的领域中重用 Service Registry 的强大基元(注册、获取、用富有表现力的过滤语言列表、等待服务的出现和消失)。这不仅节省了编写代码,还提供了全局可见性、调试工具以及比为专用解决方案实现的更多的功能。在这样的动态环境下编写代码听起来似乎是个噩梦,但幸运的是,有支持类和框架可以消除大部分(如果不是全部的话)痛苦。

  • 开发简单

CTK Plugin Framework 不仅仅是组件的标准,它还指定了如何安装和管理组件。这个 API 可以被插件用来提供一个管理代理,这个管理代理可以非常简单,如命令 shell、图形桌面应用程序、Amazon EC2 的云计算接口、或 IBM Tivoli 管理系统。标准化的管理 API 使得在现有和未来的系统中集成 CTK Plugin Framework 变得非常容易。

  • 动态更新

OSGi 组件模型是一个动态模型,插件可以在不关闭整个系统的情况下被安装、启动、停止、更新和卸载。

  • 自适应

OSGi 组件模型是从头设计的,以允许组件的混合和匹配。这就要求必须指定组件的依赖关系,并且需要组件在其可选依赖性并不总是可用的环境中生存。Service Registry 是一个动态注册表,其中插件可以注册、获取和监听服务。这种动态服务模型允许插件找出系统中可用的功能,并调整它们所能提供的功能。这使得代码更加灵活,并且能够更好地适应变化。

  • 透明性

插件和服务是 CTK 插件环境中的一等公民。管理 API 提供了对插件的内部状态的访问,以及插件之间的连接方式。可以停止部分应用程序来调试某个问题,或者可以引入诊断插件。

  • 版本控制

在 CTK Plugin Framework 中,所有的插件都经过严格的版本控制,只有能够协作的插件才会被连接在一起。

  • 简单

CTK 插件相关的 API 非常简单,核心 API 不到 25 个类。这个核心 API 足以编写插件、安装、启动、停止、更新和卸载它们,并且还包含了所有的监听类。

  • 懒加载

懒加载是软件中一个很好的点,OSGi 技术有很多的机制来保证只有当类真正需要的时候才开始加载它们。例如,插件可以用饿汉式启动,但是也可以被配置为仅当其它插件使用它们时才启动。服务可以被注册,但只有在使用时才创建。这些懒加载场景,可以节省大量的运行时成本。

  • 非独占性

CTK Plugin Framework 不会接管整个应用程序,你可以选择性地将所提供的功能暴露给应用程序的某些部分,或者甚至可以在同一个进程中运行该框架的多个实例。

  • 非侵入

在一个 CTK 插件环境中,不同插件均有自己的环境。它们可以使用任何设施,框架对此并无限制。CTK 服务没有特殊的接口需求,每个 QObject 都可以作为一个服务,每个类(也包括非 QObject)都可以作为一个接口。

为什么 CTK 不流行?

这是一个很值得深思的问题!既然 CTK Plugin Framework 借鉴了 OSGi 的思想,那么为什么 OSGi 很火,而 CTK 却鲜为人知呢?

  • 只针对医学成像和建模领域?

如果单看 CTK 简介而不做深入了解,也许会存在这样的误区。起初,CTK 的确为医学成像和建模领域准备,但并不仅限于此。作为 CTK 的核心,CTK Plugin Framework 实现了几乎完整的 OSGi 框架 API,所以只要有模块化需求,完全可以在任何 C++ 项目中使用 CTK。

  • 重量级、复杂?

CTK 包含的内容很多,Plugin Framework、Widgets、DICOM……以至于很多人认为它过于复杂、臃肿,便将其拒之门外。当然,CTK 中提供的模块有一定历史原因,因为在设计之初 CTK 针对医学成像和建模领域,其所提供的所有模块都在该领域中必不可少。

然而,这并不影响使用。如果愿意,完全可以选择对自己有用的模块。这也是我选择 CTK 的原因,因为我觉得 CTK Plugin Framework 超级棒!无论是使用框架本身,还是学习它的思想,对自己都大有益处。此外,CTK Widgets 模块还提供了各种各样自定义的炫酷部件(例如:ctkPopupWidget),简直不能太完美!

  • 缺少社区宣传

像 OSGi 这样的大型系统,除了强大的 OSGi 官网 作支撑之外,还有像 OSGi 中文社区 之类的活跃社区进行宣传,以促进 Java 模块化开发技术传播。此外,还要感谢很多大型公司和产品(例如:IBM 和 Eclipse),因为他们也在大力发展 Java 模块化,而这一切都离不开 OSGi。

但是 CTK 除了 CTK 官网CTK GitHub 之外,甚至几乎找不到任何和 CTK 相关的网站,更何况是社区了!

  • 资料匮乏

OSGi 资料多吗?搜下关键字你就知道了!

在调研 CTK 时,我曾翻阅过无数资料,打算尽快上手。但遗憾的是,网上几乎找不到任何相关信息,就连官网的资料也寥寥无几。毫不夸张的说,CTK 的资料约等于 0,所以很多时候不得不去参考 OSGi。

  • 人们更习惯于传统的开发模式

要使用 CTK,除了需要花费相应的学习成本之外,现有代码的更改也不可避免,这对开发人员来说并不具有吸引力。虽然改变意味着新生,但也伴随着痛苦与煎熬。探索未知领域,去做不熟悉的事,不是谁都可以接受的,这不仅需要勇气,还需要决心。

以上的这些问题也是 CTK 面临的一些挑战,后续是否会制定相应的发展战略来应对呢?我们不得而知,拭目以待吧!

PS: 也正因如此,才有此系列文章的诞生,希望它能够帮助更多的人了解 C++ 模块化。

第03课:入门篇——CTK Plugin Framework 基本原理

简述

CTK Plugin Framework 技术是面向 C++ 的动态模型系统。该系统允许插件之间的松散耦合,并且提供了设计良好的方式来进行功能和数据的交互。此外,它没有预先对插件施加限制,这样就可以很容易地将插件的相关部分嵌入到现有的工具包中。

体系架构

CTK Plugin Framework 设计(参考:设计文档)受到了 OSGi(Java 的动态组件系统)的极大启发,并且它提供了一种能让应用程序(动态地)由许多不同的(可重用)组件组成的开发模型。该模型允许通过服务进行通信,服务是特定于组件之间的对象。

框架的分层模型,如下图所示:

image

  • Plugins(插件):由开发人员创建的 CTK 组件;
  • Services Layer(服务层):通过为 C++ 对象提供一个 publish-find-bind 模型,以动态方式连接插件;
  • Life Cycle Layer(生命周期层):用于安装、启动、停止、更新和卸载插件的 API;
  • Security(安全性):处理安全方面(目前尚不可用)。

插件

Plugin 是 CTK Plugin Framework 的核心,模块化特性在这一层得到了很好的实现。那么,究竟什么是 Plugin?

Plugin:是基于 C++/Qt 的一个共享库,并包含了资源文件和元数据(metadata)。

image

元数据的目的在于准确描述 Plugin 的特征,除了让 CTK Plugin Framework 对 Plugin 适当地进行各种处理(例如:依赖解析)之外,还能更好的对 Plugin 进行标识,以帮助用户对 Plugin 进行理解。

元数据被定义在 MANIFEST.MF 文件中,一个典型的 MANIFEST.MF 文件如下:

Plugin-SymbolicName: HelloCTKPlugin-ActivationPolicy: eagerPlugin-Category: DemosPlugin-ContactAddress: https://github.com/WaleonPlugin-Description: A plugin for say helloPlugin-Name: HelloCTKPlugin-Vendor: WaleonPlugin-Version: 1.0.0

虽然条目众多,但并非所有的都是必须的。这些元数据主要有这两部分:

  • Plugin 的标识符(必须):唯一标识一个 Plugin,由 Plugin-SymbolicName 表示。
  • 可读的信息(可选):帮助更好地理解和使用 Plugin,不对模块化特性产生任何的影响。

对于可选信息(例如:Plugin-Name、Plugin-Vendor 等),CTK Plugin Framework 甚至会无视这些内容。

服务层

服务可以看作是服务的提供者和使用者之间的一个契约,使用者一般不关心其实现的细节,只要满足这个契约(服务应该提供什么功能、满足什么格式)就好了。使用服务的过程也包含了发现服务和达成协议的形式,也就是说,需要通过服务的标志性特征来找到对应的服务。

一个插件可以创建一个对象,并在一个或多个接口(通常是一个只有纯虚方法的 C++ 类)下使用 CTK Service Registry 注册它。其他插件可以要求 registry 列出在特定接口下注册的所有服务(对象)。一个插件甚至可以等待一个特定的服务出现,然后收到回复。

因此,一个插件可以注册一个服务,也可以获得一个服务并侦听服务的出现或消失。任意数量的插件可以在相同的接口下注册服务,并且任意数量的插件都可以得到相同的服务,如下图(publish-find-bind 模型)所示:

image

如果多个插件在同一个接口下注册对象,则可以通过其属性进行区分。每个服务注册都有一套标准的自定义属性,可以使用过滤器来选择感兴趣的服务。属性也可以被用于应用程序级的其他角色。

发布服务

为了让其它 Plugin 能发现这个服务,必须用上下文对其进行注册,需要用到接口名、服务对象(接口的具体实现)和一个可选的 ctkDictionary 类型的属性信息:

ctkDictionary properties;properties.insert("name", "Waleon");properties.insert("age", 18);ctkServiceRegistration registration = context->registerService<HelloService>(new HelloImpl(), properties);

这样,便可以得到一个 ctkServiceRegistration 对象,可以用这个对象来更新服务的属性:

registration.setProperties(newProperties);

也可以直接把这个服务移除:

registration.unregister();

注意: 这个 registration 对象不能和其他 Plugin 共享,因为它和发布服务的 Plugin 的生命周期相互依存。也就是说,如果这个 Plugin 已经不存在于框架执行环境中,那么这个对象也不应该存在了—— “皮之不存,毛将焉附”。

此外,如果在删除发布的服务之前 Plugin 停止了,框架会帮助你删除这些服务。

获取服务

一旦服务被发布,它将对其他 Plugin 可用。获取服务的方式非常简单,只需要提供一个接口名即可:

ctkServiceReference reference = context->getServiceReference<HelloService>();

注意: 这里的 reference 是服务对象的间接引用,可为什么要用间接引用而不直接返回实际的服务对象呢?

实际上,这是为了将服务的使用和服务的实现进行解耦。将服务注册表作为两者的中间人,不仅能够达到跟踪和控制服务的目的,同时还可以在服务消失以后通知使用者。

这个方法的返回类型是 ctkServiceReference,它可以在 Plugin 之间互享,因为它和使用服务的 Plugin 的生命周期无关。

生命周期层

生命周期层主要用于控制 Plugin 的安装、启动、停止、更新和卸载,它可以让我们从外部管理应用或者建立能够自我管理的应用(或将两者相结合),并且给了应用本身很大的动态性。

前面已经了解了 Plugin 的概念和作用,但要真正使用 Plugin,则需要使用生命周期层的 API 来和 CTK Plugin Framework 的生命周期层进行交互。

下图为 Plugin 生命周期的状态转换图:

image

生命周期层的 API 主要由三个核心部分组成:ctkPluginActivator、ctkPluginContext 和 ctkPlugin。

ctkPluginActivator

ctkPluginActivator:自定义 plugin 的启动和停止。

ctkPluginActivator 是一个接口,必须由框架中的每个插件实现。框架可以根据需要创建一个插件的 ctkPluginActivator 实例。如果一个实例的 ctkPluginActivator::start() 方法成功执行,则需要保证在插件停止时调用同一个实例的 ctkPluginActivator::stop() 方法。

ctkPluginContext

ctkPluginContext:一个 plugin 在框架内的执行上下文,该上下文用于授予对其他方法的访问,以便该插件可以与框架交互。

ctkPluginContext 提供的方法允许插件:

  • 订阅由框架发布的事件;
  • 使用 Framework Service Registry 注册服务对象;
  • 从 Framework Service Registry 检索 ServiceReferences;
  • 为引用的服务获取和发布服务对象;
  • 在框架中安装新的插件;
  • 获取框架中安装的插件列表;
  • 获得一个插件的 ctkPlugin 对象;
  • 为(由框架为插件提供的)持久存储区域中为文件创建 QFile 对象。

当使用 ctkPluginActivator::start() 方法启动时,将创建一个 ctkPluginContext 对象,并将其提供给与此上下文关联的插件。当使用 ctkPluginActivator::stop() 方法停止时,相同的 ctkPluginContext 对象将被传递给与此上下文关联的插件。ctkPluginContext 对象通常用于其关联插件的私有用途,并不意味着与插件环境中的其他插件共享。

与 ctkPluginContext 对象关联的 ctkPlugin 对象称为上下文插件。

ctkPluginContext 对象只有在它的上下文插件执行时才有效;也就是说,在上下文插件处于 STARTING、STOPPING、和 ACTIVE 状态的时段内。如果随后使用 ctkPluginContext 对象,则必须抛出一个 ctkIllegalStateException 异常。当上下文插件停止后,ctkPluginContext 对象不能被重用。

Framework 是唯一能够创建 ctkPluginContext 对象的实体,并且这些对象只在创建它们的 Framework 中有效。

ctkPlugin

ctkPlugin:Framework 中已安装的插件。

ctkPlugin 对象是定义一个已安装插件的生命周期的访问点,在插件环境中安装的每个插件都必须有一个相关的 ctkPlugin 对象。此外,插件必须有一个唯一的标识,在插件的生命周期中,这个标识不能改变(即使是在插件更新时),卸载和重新安装插件必须创建一个新的唯一标识。

插件有以下状态(状态是动态可变的,这些状态在特定条件下可以互相转换,见上图):

  • UNINSTALLED
  • INSTALLED
  • RESOLVED
  • STARTING
  • STOPPING
  • ACTIVE

要确定插件是否处于有效状态之一,可以使用 States 类型进行“或”运算。

插件只能在状态为 STARTING、ACTIVE 或 STOPPING 状态时执行代码。一个 UNINSTALLED 插件不能被设置为另一个状态,它是一个“僵尸”。

框架是唯一允许创建 ctkPlugin 对象的实体,并且这些对象仅在创建它们的框架内有效。

第04课:进阶篇——编译 CTK
第05课:进阶篇——使用 CTKWidgets
第06课:进阶篇——Hello,CTK!
第07课:进阶篇——在程序中嵌入 CTK Plugin Framework
第08课:进阶篇——CTK 插件元数据
第09课:进阶篇——CTK 插件和服务
第10课:进阶篇——CTK 插件之间的依赖
第11课:高级篇——CTK 事件管理机制(上)
第12课:高级篇——CTK 事件管理机制(中)
第13课:高级篇——CTK 事件管理机制(下)
第14课:高级篇——CTK 服务工厂
第15课:高级篇——CTK 事件与监听
第16课:高级篇——CTK 服务追踪
第17课:高级篇——访问 CTK 服务的最佳方式
第18课:总结 FAQ

阅读全文: http://gitbook.cn/gitchat/column/5ad02029f8164454a34a089b

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页