大家好,又见面了,我是你们的朋友全栈君。
目录
二、CTK Plugin Framework架构及插件的使用
CTK Plugin Framework简介
框架简介
1.1、简介
CTK Plugin Framework设计参考了OSGi(Open Service Gateway Initiative,开放服务网关协议)(Java的动态组件系统),并提供了一种能让应用程序(动态地)由许多不同的可重用组件组成的开发模型,允许通过服务进行通信。
OSGi规范的核心部分是一个框架,核心框架定义了应用程序的生命周期模式和服务注册。基于OSGI核心框架定义了大量的OSGi服务:日志、配置管理、HTTP(运行servlet)、XML分析、设备访问、软件包管理、许可管理、用户管理、IO连接、连线管理、Jini和UPnP。
CTK Plugin Framework框架的分层模型如下:
Plugins(插件):由开发人员创建的CTK组件;
Services Layer(服务层):通过为C++对象提供一个publish-find-bind模型,以动态方式连接插件;
Life Cycle Layer(生命周期层):用于安装、启动、停止、更新和卸载插件的API;
D、Security(安全性):处理安全方面。
1.2、插件模块层
Plugin是CTK Plugin Framework的核心,是模块化特性的体现。
插件由插件激活器类Activator启动,激活器可以获取代表插件框架的插件上下文环境,插件上下文对象不能共享。
Plugin是基于C++/Qt的一个共享库,包含了资源文件和元数据(metadata)。元数据的目的在于准确描述Plugin的特征,除了让CTK Plugin Framework对Plugin适当地进行各种处理(例如:依赖解析)外,还能更好的对Plugin进行标识,以帮助用户对Plugin进行理解。
元数据被定义在MANIFEST.MF文件中,典型的MANIFEST.MF文件如下:
Plugin-SymbolicName: HelloCTK
Plugin-ActivationPolicy: eager
Plugin-Category: demo
Plugin-ContactAddress: https://github.com/scorpiostudio
Plugin-Description: A plugin for say hello
Plugin-Name: HelloCTK
Plugin-Vendor: scorpio
Plugin-Version: 1.0.0
元数据主要分为两部分:
一、Plugin的标识符(必须):唯一标识一个 Plugin,由Plugin-SymbolicName表示。
二、可读信息(可选):帮助更好地理解和使用Plugin,不对模块化特性产生任何的影响。可选信息如Plugin-Name、Plugin-Vendor。
1.3、服务层
CTK插件框架提供了插件间通信的动态服务模型,一个激活的插件可以在任何时候注册(注销)0个或多个服务到框架。服务注册是一个具有可选注册属性的发布接口。通过接口和过滤表达式可以从插件框架获得服务引用。框架发布服务生命周期事件。
服务可以通过ctkPluginContext对象注册到插件框架。服务的注册和注销可以在任何时候进行。
服务是服务的提供者和使用者之间的一个契约,使用者一般不关心其实现的细节,只关心是否满足契约(服务应该提供什么功能、满足什么格式)。使用服务的过程包含了发现服务和达成协议的形式,即需要通过服务的标志性特征来找到对应的服务。
一个插件可以创建一个对象,并在一个或多个接口(通常是一个只有纯虚方法的C++类)下使用CTK Service Registry注册它。其它插件可以要求registry列出在特定接口下注册的所有服务(对象)。一个插件甚至可以等待一个特定的服务出现,然后收到回复。
因此,一个插件可以注册一个服务,也可以获得一个服务并侦听服务的出现或消失。任意数量的插件可以在相同的接口下注册服务,并且任意数量的插件都可以得到相同的服务。
publish-find-bind模型如下:
如果多个插件在同一个接口下注册对象,则可以通过其属性进行区分。每个服务注册都有一套标准的自定义属性,可以使用过滤器来选择感兴趣的服务。属性也可以被用于应用程序级的其他角色。
一、发布服务
为了让其它Plugin能发现服务,必须用上下文对其进行注册,需要用到接口名、服务对象(接口的具体实现)和一个可选的ctkDictionary类型的属性信息:
ctkDictionary properties;
properties.insert(“name”, “scorpio”);
properties.insert(“age”, 30);
ctkServiceRegistration registration = context->registerService<HelloService>(new HelloServiceImpl(), properties);
得到一个ctkServiceRegistration对象,用于更新服务的属性:
registration.setProperties(newProperties);
注销服务:
registration.unregister();
registration对象不能和其它Plugin共享,因为registration对象和发布服务的Plugin的生命周期相互依存。如果Plugin已经不存在于框架执行环境中,那么registration对象也不应该存在。
此外,如果在删除发布的服务前Plugin停止,框架会帮助删除这些服务。
二、获取服务
一旦服务被发布,服务将对其他Plugin可用。获取服务的方式非常简单,只需要提供一个接口名即可:
ctkServiceReference reference = context->getServiceReference<HelloService>();
reference对象是服务对象的间接引用。间接引用可以将服务的使用和服务的实现进行解耦。将服务注册表作为两者的中间人,不仅能够达到跟踪和控制服务的目的,同时还可以在服务消失以后通知使用者。
接口的返回类型是ctkServiceReference,可以在Plugin之间互享,因为reference对象和使用服务的Plugin的生命周期无关。
1.4、生命周期层
生命周期层主要用于控制Plugin的安装、启动、停止、更新和卸载,可以从外部管理应用或者建立能够自我管理的应用(或将两者相结合),并且给了应用本身很大的动态性。
Plugin的使用需要使用生命周期层的API来和CTK Plugin Framework的生命周期层进行交互。
Plugin生命周期的状态转换图:
生命周期层的API主要由三个核心部分组成:ctkPluginActivator、ctkPluginContext和ctkPlugin。
(1)、ctkPluginActivator
ctkPluginActivator:自定义plugin的启动和停止。
ctkPluginActivator是一个接口,必须由框架中的每个插件实现。插件必须提供一个由插件框架调用的插件激活器类。框架可以根据需要创建一个插件的ctkPluginActivator实例。如果一个实例的ctkPluginActivator::start()方法成功执行,则需要保证在插件停止时调用同一个实例的ctkPluginActivator::stop() 方法。
当插件进入ACTIVE状态时,框架会调用start方法,当插件离开ACTIVE状态时,插件框架会调用stop方法。每一个插件都会接收到一个访问插件框架的唯一ctkPluginContext对象。
(2)、ctkPluginContext
ctkPluginContext是一个plugin在框架内的执行上下文,用于授予对其它方法的访问,以便该插件可以与框架交互。ctkPluginContext提供的方法允许插件:
A、订阅由框架发布的事件;
B、使用Framework Service Registry注册服务对象;
C、从Framework Service Registry检索ServiceReferences;
D、为引用的服务获取和发布服务对象;
E、在框架中安装新的插件;
F、获取框架中安装的插件列表;
G、获得一个插件的ctkPlugin对象;
H、为(由框架为插件提供的)持久存储区域中为文件创建QFile对象。
当使用ctkPluginActivator::start()方法启动时,将创建一个 ctkPluginContext对象,并将其提供给与此上下文关联的插件。当使用ctkPluginActivator::stop()方法停止时,相同的ctkPluginContext对象将被传递给与此上下文关联的插件。ctkPluginContext对象通常用于其关联插件的私有用途,并不意味着与插件环境中的其它插件共享。
与ctkPluginContext对象关联的ctkPlugin对象称为上下文插件。
ctkPluginContext对象只有在它的上下文插件执行时才有效;即在上下文插件处于STARTING、STOPPING和ACTIVE状态的时段内。如果随后使用ctkPluginContext对象,则必须抛出一个ctkIllegalStateException异常。当上下文插件停止后,ctkPluginContext对象不能被重用。
Framework是唯一能够创建ctkPluginContext对象的实体,并且ctkPluginContext对象只在创建它们的Framework中有效。
(3)、ctkPlugin
ctkPlugin是Framework中已安装的插件。
ctkPlugin对象是定义一个已安装插件的生命周期的访问点,在插件环境中安装的每个插件都必须有一个相关的ctkPlugin对象。此外,插件必须有一个唯一的标识,在插件的生命周期中,唯一标识不能改变(即使是在插件更新时),卸载和重新安装插件必须创建一个新的唯一标识。
插件有以下状态(状态是动态可变的,在特定条件下可以互相转换):
UNINSTALLED
INSTALLED
RESOLVED
STARTING
STOPPING
ACTIVE
要确定插件是否处于有效状态之一,可以使用States类型进行“或”运算。
插件只能在状态为STARTING、ACTIVE或STOPPING状态时执行代码。一个UNINSTALLED插件是一个僵尸,不能被设置为另一个状态。
框架是唯一允许创建ctkPlugin对象的实体,并且ctkPlugin对象仅在创建它们的框架内有效。
2、框架实现
CTK Plugin Framework基于Qt Plugin System和Qt Service Framework实现,并且增加了插件元数据(由MANIFEST.MF文件提供)、定义良好的插件生命周期和上下文、综合服务发现和注册特性来扩展。
在Qt Plugin System中,插件的元数据由JSON文件提供。CTK Plugin Framework的核心架构主要包含两个组件:Plugin System和Service Registry。这两个组件是相互关联的,在API级别上的组合使得系统更加全面、灵活。
2.1、Plugin System
CTK Core依赖于QtCore模块,因此CTK Plugin Framework基于Qt Plugin System。Qt API允许在运行时加载和卸载插件,热插拔功能在CTK Plugin Framework中得到了加强,以支持透明化延迟加载和解决依赖关系。
插件的元数据被编译进插件内部,可以通过API进行提取。此外,插件系统还使用SQLite缓存了元数据,以避免应用程序加载时间问题。另外,Plugin System支持通过中央注册中心使用服务。
2.2、Service Registry
Qt Service Framework是Qt Mobility项目发布的一个Qt 解决方案,Qt服务框架允许“声明式服务”和按需加载服务实现。为了启用动态(非持久性)服务,Qt Mobility服务框架可以与Service Registry一起使用。
3、框架优点
CTK Plugin Framework以OSGi规范为模型,并实现了几乎完整的OSGI框架API,因此使用CTK Plugin Framework开发基于Qt的C++应用程序有如下优点:
3.1、降低复杂性
使用CTK Plugin Framework进行应用开发只需进行插件开发,插件隐藏了内部实现,并通过定义良好的服务来和其它插件通信。隐藏内部机制意味着可以自由地更改实现,不仅有助于Bug数量的减少,还使得插件的开发变得更加简单,因为只需要实现已经定义好的一定数量的功能接口即可。
3.2、可复用
标准化的组件模型,在应用程序中使用第三方组件变得非常简单。
3.3、版本控制
在CTK Plugin Framework中,所有的插件都经过严格的版本控制,只有能够协作的插件才会被连接在一起。
3.4、动态更新
OSGi组件模型是一个动态模型,插件可以在不关闭整个系统的情况下被安装、启动、停止、更新和卸载。
3.5、自适应
OSGi组件模型是从头设计的,以允许组件的混合和匹配,要求必须指定组件的依赖关系,并且需要组件在其可选依赖性并不总是可用的环境中生存。Service Registry是一个动态注册表,其中插件可以注册、获取和监听服务。OSGI动态服务模型允许插件找出系统中可用的功能,并调整它们所能提供的功能,使得代码更加灵活, 并且能够更好地适应变化。
3.6、透明性
插件和服务是CTK插件环境中的一等公民。管理API提供了对插件的内部状态的访问,以及插件之间的连接方式。可以停止部分应用程序来调试某个问题,或者可以引入诊断插件。
3.7、开发简单
CTK插件相关的API非常简单,核心API不到25个类。核心API足以编写插件、安装、启动、停止、更新和卸载,并且还包含了所有的监听类。
CTK Plugin Framework不仅仅是组件的标准,还指定了如何安装和管理组件的API。API可以被插件用来提供一个管理代理,管理代理可以非常简单,如命令shell、图形桌面应用程序、Amazon EC2的云计算接口、或IBM Tivoli管理系统。标准化的管理API 使得在现有和未来的系统中集成CTK Plugin Framework变得非常容易。
3.8、懒加载
OSGi技术有很多的机制来保证只有当类真正需要的时候才开始加载插件。例如,插件可以用饿汉式启动,但是也可以被配置为仅当其它插件使用它们时才启动。服务可以被注册,但只有在使用时才创建。懒加载场景可以节省大量的运行时成本。
3.9、非独占性
CTK Plugin Framework不会接管整个应用程序,可以选择性地将所提供的功能暴露给应用程序的某些部分,或者甚至可以在同一个进程中运行该框架的多个实例。
3.10、非侵入
在一个CTK插件环境中,不同插件均有自己的环境。插件可以使用任何设施,框架对此并无限制。CTK服务没有特殊的接口需求,每个QObject都可以作为一个服务,每个类(包括非QObject)都可以作为一个接口。
4、CTK事件管理机制
框架使用事件机制来通知各个插件,系统中插件的安装、卸载、解析、启动、停止等状态的切换[5]。
4.1、框架事件
4.2、插件事件
4.3、服务事件
4.4、自定义事件
在 CTK 中,插件之间的通信,可以通过 Event Admin 来完成。Event Admin 是一种基于发布/订阅的方式,一个插件订阅某一主题之后,另一个插件发布一个与该主题相关的事件,从而达到通信的目的。
二、CTK Plugin Framework架构及插件的使用
1、CTK Plugin Framework使用流程
2、创建CTK插件
3、CTK插件框架使用实例
参考
- https://commontk.org/index.php/Main_Page
- https://gitbook.cn/gitchat/column/5ad02029f8164454a34a089b
- http://www.mamicode.com/info-detail-2318577.html
- https://blog.csdn.net/xinqidian2015/article/details/50537325
- https://www.cnblogs.com/judes/p/13272104.html
- https://blog.csdn.net/zfy920323/article/details/79265289?utm_source=blogxgwz0
- https://blog.csdn.net/slwstc/article/details/55252466
- https://blog.csdn.net/zfy920323/article/details/79275351?utm_source=blogxgwz1
- http://www.voidcn.com/article/p-tlxdqygb-bqt.html
- https://blog.csdn.net/westlor/article/details/103979363
- https://gitee.com/iotmedical/CTK-examples
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/135812.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...