编辑推荐: |
本文主要CTK Plugin Framework是什么?它的体系结构,服务层以及它的生命周期等等相关内容。
文章来自于csdn,由火龙果Anna编辑推荐。 |
|
“CTK Plugin Framework 技术是面向 C++ 的动态模型系统。该系统允许插件之间的松散耦合,并且提供了设计良好的方式来进行功能和数据的交互。此外,它没有预先对插件施加限制,这样就可以很容易地将插件的相关部分嵌入到现有的工具包中。”
体系架构
CTK Plugin Framework 设计受到了 OSGi(Java 的动态组件系统)的极大启发,并且它提供了一种能让应用程序(动态地)由许多不同的(可重用)组件组成的开发模型。该模型允许通过服务进行通信,服务是特定于组件之间的对象。
框架的分层模型,如下图所示:
Plugins(插件):由开发人员创建的 CTK 组件;
Services Layer(服务层):通过为 C++ 对象提供一个 publish-find-bind
模型,以动态方式连接插件;
Life Cycle Layer(生命周期层):用于安装、启动、停止、更新和卸载插件的 API;
Security(安全性):处理安全方面(目前尚不可用)。
插件
Plugin 是 CTK Plugin Framework 的核心,模块化特性在这一层得到了很好的实现。那么,究竟什么是
Plugin?
Plugin:是基于 C++/Qt 的一个共享库,并包含了资源文件和元数据(metadata)。
元数据的目的在于准确描述 Plugin 的特征,除了让 CTK Plugin Framework
对 Plugin 适当地进行各种处理(例如:依赖解析)之外,还能更好的对 Plugin 进行标识,以帮助用户对
Plugin 进行理解。
元数据被定义在 MANIFEST.MF 文件中,一个典型的 MANIFEST.MF
文件如下:
Plugin-SymbolicName:HelloCTK
Plugin-ActivationPolicy:eager
Plugin-Category:Demos
Plugin-ContactAddress:https://github.com/Waleon
Plugin-Description:A plugin for say hello
Plugin-Name:HelloCTK
Plugin-Vendor:Waleon
Plugin-Version:1.0.0 |
虽然条目众多,但并非所有的都是必须的。这些元数据主要包含两部分:
Plugin 的标识符(必须):唯一标识一个 Plugin,由 Plugin-SymbolicName
表示。
可读的信息(可选):帮助更好地理解和使用 Plugin,不对模块化特性产生任何的影响。
对于可选信息(例如:Plugin-Name、Plugin-Vendor 等),CTK Plugin
Framework 甚至会无视这些内容。
服务层
服务可以看作是服务的提供者和使用者之间的一个契约,使用者一般不关心其实现的细节,只要满足这个契约(服务应该提供什么功能、满足什么格式)就好了。使用服务的过程也包含了发现服务和达成协议的形式,也就是说,需要通过服务的标志性特征来找到对应的服务。
一个插件可以创建一个对象,并在一个或多个接口(通常是一个只有纯虚方法的 C++ 类)下使用 CTK
Service Registry 注册它。其他插件可以要求 registry 列出在特定接口下注册的所有服务(对象)。一个插件甚至可以等待一个特定的服务出现,然后收到回复。
因此,一个插件可以注册一个服务,也可以获得一个服务并侦听服务的出现或消失。任意数量的插件可以在相同的接口下注册服务,并且任意数量的插件都可以得到相同的服务,如下图(publish-find-bind
模型)所示:
如果多个插件在同一个接口下注册对象,则可以通过其属性进行区分。每个服务注册都有一套标准的自定义属性,可以使用过滤器来选择感兴趣的服务。属性也可以被用于应用程序级的其他角色。
发布服务
为了让其它 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 生命周期的状态转换图:
生命周期层的 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
插件不能被设置为另一个状态,它是一个“僵尸”。
Framework 是唯一允许创建 ctkPlugin 对象的实体,并且这些对象仅在创建它们的 Framework?内有效。
|