CTK框架(八):服务追踪
目录
1.简介
2.实现方式
3.具体实现
3.1.新建插件PluginA
3.2.新建插件PluginB
4.服务追踪的优势
5.应用场景
6.总结
1.简介
CTK服务追踪是一种机制,用于在CTK插件框架中追踪和管理插件提供的服务。当一个插件注册了一个服务到服务注册中心后,其他插件可以通过服务追踪机制来发现、获取和使用这个服务。服务追踪简化了服务的获取过程,解决了无法监听已存在服务的问题。
如果想在B插件里使用A服务,可以专门写一个类继承ctkServiceTracker,在这个类里完成对A服务的底层操作,然后在B插件里通过这个类提供的接口来使用回收A服务。

2.实现方式
ctkServiceTracker是CTK提供的一个类,用于追踪服务。开发者可以创建一个继承自ctkServiceTracker的类,并实现相应的接口或方法,以完成对特定服务的追踪。当服务注册或注销时,ctkServiceTracker会收到通知,并更新内部的服务引用列表。
具体步骤为:
- 注册服务:插件A实现了一个服务,并在其激活类中将该服务注册到服务注册中心。
- 创建服务追踪器:插件B需要使用插件A提供的服务,因此插件B在其激活类中创建一个ctkServiceTracker的实例,用于追踪插件A提供的服务。
- 监听服务变化:ctkServiceTracker会监听服务注册中心的变化,当插件A提供的服务可用时,它会将服务引用添加到内部列表中,并通知插件B。
- 获取并使用服务:插件B通过ctkServiceTracker获取插件A提供的服务引用,并使用该服务。
3.具体实现
3.1.新建插件PluginA
CTK框架(四): 插件编写-CSDN博客
在CTK框架(四): 插件编写里面介绍了PluginA的编写,不清楚的可以去翻翻看。
3.2.新建插件PluginB
因为真正使用到A服务的地方就是B插件的实现类里,所以通过构造函数把tracker给传进去。这里的tracker是在激活类里new的,因为context是从实现类里传进来的,根据这个思路也可把context传到B的实现类里,再在实现类里new出tracker。
ctkServiceTracker里主要实现以下三个接口,注意ctkServiceTracker是一个模板类,需要指明主要追踪的服务类名。
template<class S = QObject*, class T = S>
class ctkServiceTracker : protected ctkServiceTrackerCustomizer<T>
{//...
protected:virtual T addingService(const ctkServiceReference& reference) = 0;virtual void modifiedService(const ctkServiceReference& reference, T service) = 0;virtual void removedService(const ctkServiceReference& reference, T service) = 0;//...
};
插件结构:
PluginBService:接口类
PluginBImpl:实现类
PluginBActivator:激活类
ServiceTracker:追踪类
接口类:PluginBService
#ifndef PLUGINB_SERVICE_H
#define PLUGINB_SERVICE_H#include <QtPlugin>class PluginBService
{
public:virtual ~PluginBService() {}virtual void B_Func() = 0;
};#define PluginBService_iid "org.commontk.service.demos.PluginBService"
Q_DECLARE_INTERFACE(PluginBService, PluginBService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINB_SERVICE_H
实现类:PluginBImpl
#ifndef PLUGINB_IMPL_H
#define PLUGINB_IMPL_H#include "PluginBService.h"
#include <QObject>class ServiceTracker;class PluginBImpl : public QObject, public PluginBService
{Q_OBJECTQ_INTERFACES(PluginBService)/*此宏与Q_DECLARE_INTERFACE宏配合使用。Q_DECLARE_INTERFACE:声明一个接口类Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类*/public:PluginBImpl(ServiceTracker *tracker);void B_Func() Q_DECL_OVERRIDE;private:ServiceTracker *m_pTracker;
};#endif // PLUGINB_IMPL_H
#include "PluginBImpl.h"
#include <QtDebug>
#include "../PluginA/PluginAService.h"
#include "ServiceTracker.h"PluginBImpl::PluginBImpl(ServiceTracker *tracker): m_pTracker(tracker)
{QString currPath = QCoreApplication::applicationDirPath();qDebug() << "PluginB current path : " << currPath;
}void PluginBImpl::B_Func()
{QString currPath = QCoreApplication::applicationDirPath();qDebug() << "PluginB current path1 : " << currPath;PluginAService* service = static_cast<PluginAService*>(m_pTracker->getService());if (service != Q_NULLPTR) {service->A_Func();}else {qDebug()<<"get AbsPrintServer from tracker failed";}
}
激活类:PluginBActivator
#ifndef PLUGINBACTIVATOR_H
#define PLUGINBACTIVATOR_H
#include <QObject>
#include "ctkPluginActivator.h"
#include "PluginBService.h"class PluginBImpl;
class ServiceTracker;class PluginBActivator : public QObject, public ctkPluginActivator
{Q_OBJECTQ_INTERFACES(ctkPluginActivator)Q_PLUGIN_METADATA(IID "PLUGINB")//向Qt的插件框架声明,希望将xxx插件放入到框架中。public:void start(ctkPluginContext* context);void stop(ctkPluginContext* context);private:PluginBImpl *m_pPlugin;ServiceTracker* m_pTracker;ctkServiceRegistration m_registration;
};
#endif // PLUGINBACTIVATOR_H
#include "PluginBActivator.h"
#include "PluginBImpl.h"
#include "ServiceTracker.h"
#include <QDebug>void PluginBActivator::start(ctkPluginContext* context)
{// 开启服务跟踪器m_pTracker = new ServiceTracker(context);m_pTracker->open();m_pPlugin = new PluginBImpl(m_pTracker);m_registration = context->registerService<PluginBService>(m_pPlugin);
}void PluginBActivator::stop(ctkPluginContext* context)
{Q_UNUSED(context)//Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用// 注销服务m_registration.unregister();// 关闭服务跟踪器m_pTracker->close();delete m_pPlugin;m_pPlugin = Q_NULLPTR;
}
追踪类:ServiceTracker
#ifndef SERVICETRACKER_H
#define SERVICETRACKER_H
#include <ctkPluginContext.h>
#include <ctkServiceTracker.h>
#include "../PluginA/PluginAService.h"class ServiceTracker : public ctkServiceTracker<PluginAService *>
{
public:ServiceTracker(ctkPluginContext* context) : ctkServiceTracker<PluginAService *>(context) {}~ServiceTracker() {}protected:// 在 Service 注册时访问PluginAService* addingService(const ctkServiceReference& reference) Q_DECL_OVERRIDE {qDebug() << "Adding service:" << reference.getPlugin()->getSymbolicName();PluginAService* service = (PluginAService*)(ctkServiceTracker::addingService(reference));return service;}void modifiedService(const ctkServiceReference& reference, PluginAService* service) Q_DECL_OVERRIDE {qDebug() << "Modified service:" << reference.getPlugin()->getSymbolicName();ctkServiceTracker::modifiedService(reference, service);}void removedService(const ctkServiceReference& reference, PluginAService* service) Q_DECL_OVERRIDE {qDebug() << "Removed service:" << reference.getPlugin()->getSymbolicName();ctkServiceTracker::removedService(reference, service);}
};
#endif // SERVICETRACKER_H
测试
我们在B插件的实现类中的B_Func()接口中,通过服务追踪调用了服务A的接口A_Func(),如下:

启用插件,然后调用B_Func(),修改main.cpp,添加如下代码段
//启用A插件
try {// 安装插件QString PluginA_dir = "D:/openCode/ctkcreator/bin/qmake/debug/plugins/PluginA.dll";QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginA_dir));qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());// 启动插件plugin->start(ctkPlugin::START_TRANSIENT);qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {qDebug() << QString("Failed install or run plugin: ") << e.what();return -2;
}//启用B插件
try {// 安装插件QString PluginB_dir = "D:/openCode/ctkcreator/bin/qmake/debug/plugins/PluginB.dll";QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(PluginB_dir));qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());// 启动插件plugin->start(ctkPlugin::START_TRANSIENT);qDebug() << QString("Plugin[%1_%2] started").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
} catch (const ctkPluginException &e) {qDebug() << QString("Failed install or run plugin: ") << e.what();return -2;
}// 获取服务引用
ctkServiceReference reference = pluginContext->getServiceReference<PluginBService>();
if (reference) {// 获取指定 ctkServiceReference 引用的服务对象PluginBService* service = pluginContext->getService<PluginBService>(reference);if (service != Q_NULLPTR) {// 调用服务service->B_Func();}
}
输出:
Adding service: "PluginA"
PluginB current path : "D:/openCode/ctkcreator/bin/qmake/debug"
PluginB current path1 : "D:/openCode/ctkcreator/bin/qmake/debug"
A_Func()
可以看到在插件B中成功通过服务追踪,调用了服务A的接口A_Func()
4.服务追踪的优势
1)简化服务获取:通过服务追踪,插件可以更容易地获取其他插件提供的服务,无需编写复杂的代码来监听服务变化。
2)提高系统灵活性:服务追踪使得插件之间的依赖关系更加灵活,插件可以在运行时动态地发现和使用其他插件提供的服务。
3)支持动态服务:由于服务追踪可以监听服务注册中心的变化,因此它支持动态服务的注册和注销,使得系统更加健壮和灵活。
5.应用场景
CTK服务追踪在基于CTK插件框架的应用程序中具有广泛的应用场景,例如:
- 日志服务:一个插件提供日志服务,其他插件通过服务追踪机制来获取和使用这个日志服务来记录日志信息。
- 认证服务:一个插件实现用户认证功能,其他插件通过服务追踪机制来获取和使用这个认证服务来进行用户认证。
- 数据共享:插件之间通过服务追踪机制来共享数据或资源,实现数据的互通和共享。
6.总结
CTK服务追踪是CTK插件框架中一个重要的功能,它允许开发者追踪和管理插件提供的服务。通过服务追踪机制,插件可以更容易地获取和使用其他插件提供的服务,从而提高系统的灵活性和可扩展性。在实际开发中,开发者可以根据需要创建自定义的服务追踪器来实现对特定服务的追踪和管理。
相关文章:
CTK框架(八):服务追踪
目录 1.简介 2.实现方式 3.具体实现 3.1.新建插件PluginA 3.2.新建插件PluginB 4.服务追踪的优势 5.应用场景 6.总结 1.简介 CTK服务追踪是一种机制,用于在CTK插件框架中追踪和管理插件提供的服务。当一个插件注册了一个服务到服务注册中心后࿰…...
[针对于个人用户] 显卡与计算卡性能对比表
笔者使用 Quadro M4000 显卡用于 LLM 相关任务,但奈何该卡发布的年代过于久远,以至于 LLM 相关任务只能使用例如:Phi3 mini、Qwen 2 2B、GLM 4 8B 以及 Gemini v2 2B等小参数模型,且速度不堪理想,也经常因为显卡过热降…...
2024年智能录屏解决方案全攻略,从桌面到云端
如果你有过录屏经验那你一定遇到过被限制录制时长或者录制的画面比较模糊之类的情况。这次我我推荐几款免费录屏软件,让我们可以更自由的录制屏幕画面。 1.福晰REC大师 链接:www.foxitsoftware.cn/REC/ 这款软件便捷好操作,而且符合我这次…...
CentOS7.9下snmp v3 inform搭建监控端
1.基础环境配置 为了防止防火墙及selinux等的影响,需关闭防火墙及selinux等,具体参考: Linux常规基础配置_linux基础配置-CSDN博客 2.安装snmp yum源配置,具体参考: Linux常规基础配置_linux基础配置-CSDN博客 snmp安装命令: yum install -y net-snmp net-snmp-ut…...
水库大坝安全监测方案,双重守护,安全无忧
水库作为重要的水利设施,在防洪、灌溉及供水等方面发挥着重要作用。然而随着时间的推移,大坝面临着自然老化、设计标准不足及极端天气等多重挑战,其安全性与稳定性日益受到关注。水库堤坝险情导致的洪涝灾害给人民生命财产和经济社会发展带来…...
yolov8实现图片验证码识别
1、环境准备 1.1、安装miniconda 地址:Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 注意:为避免不兼容的问题,推荐下载py38版本,我下载的是Miniconda3-py38_23.1.0-1-Windows-x86_…...
代码随想录训练营 Day56打卡 图论part06 108. 冗余连接 109. 冗余连接II
代码随想录训练营 Day56打卡 图论part06 一、卡码108. 冗余连接 题目描述 有一个图,它是一棵树,他是拥有 n 个节点(节点编号1到n)和 n - 1 条边的连通无环无向图(其实就是一个线形图),如图&…...
QT天气预报
json 理论 什么是JSON? 规则 被大括号包括的是JSON对象,被中括号包括的是JSON数组. JSON数组JSON对象 实验 构建JSON 用代码实现如下json内容: //构建JSON void WirteJson() {QJsonObject rootObject;//1.插入name字段rootObject.insert("name","china&quo…...
JavaWeb中处理 Web 请求的方式总结
文章目录 JavaWeb中处理 Web 请求的方式总结1. 原始的 Servlet 方式1.1. 环境搭建**创建 Maven 或 Gradle 项目**:**添加 Servlet 依赖**:**创建 Servlet 类**:**配置项目**:**配置 Tomcat**: 1.2. 路由机制1.3. 示例代…...
React的事件与原生事件的执行顺序?
react自身实现了一套自己的事件机制,包括事件注册、事件的合成、事件冒泡、事件派发等,虽然和原生的是两码事,但也是基于浏览器的事件机制下完成的。 react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上,然后由…...
【Java】Runtime与Properties获取系统信息
Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容:三、问题描述四、解决方案:4.1 代码4.2 运行结果 五、总结: 一、前言 这些都被淘汰比较少用了…...
基于SpringBoot的社团管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于JavaSpringBootVueMySQL的社团管理系统【附源码文档】、…...
UE5.3_跟一个插件—Socket.IO Client
网上看到这个插件,挺好! 项目目前也没有忙到不可开交,索性跟着测一下吧: 商城可见,售价72.61人民币! 但是,git上有仓库哦,免费!! 跟着链接先准备起来: Documentation: GitHub - getnamo/SocketIOClient-Unreal: Socket.IO client plugin for the Unreal Engin…...
鸿蒙轻内核A核源码分析系列七 进程管理 (1)
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 轻内核A核源码分析系列一 数据结构-双向循环链表 轻内核A核源码分析系列二 数据结构-位图操作 轻内核A核源码分析系列三 物理内存(1࿰…...
qt QGraphicsScene场景坐标和场景内GraphicsItem局部坐标的相互转换
为了更清晰地解释场景坐标与局部坐标之间的转换过程,我们可以通过一个简单的实例来演示如何赋值场景坐标,并将其转换为图形项的局部坐标。 实例步骤 假设我们有一个场景 QGraphicsScene 和一个矩形图形项 QGraphicsRectItem,矩形的大小为 1…...
Windows与linux中docker的安装与使用
windos中安装使用docker 下载Docker_Desktop 安装包进入docker官网下载Docker_Desktop: https://www.docker.com/启用wsl 我们搜索“启用或关闭Windows功能”,打开后勾选适用于Linux的Windows 子系统 Docker_Desktop设置 出现Docker Engine stopp…...
some electronic products
纽扣电池 button cell 运动手环 sports wristband 智能手环 smart bracelet 皮卡丘夜灯 pikachu night lamp 数字显示充电器 Charger with a digital display 磁吸无线充 magnetic wireless charger 直流电机调速器 DC motor speed controller 继电器模块 relay module 锂离子电…...
刘润《关键跃升》读书笔记7
沟通: 想明⽩,说清楚,能接受 团队沟通的正确⽅式可以⽤9个字来概括:想明⽩,说清楚,能接受 (⻅图4-1)想明⽩ 有时经理跟⼈沟通,讲完之后却⽆奈地对员⼯说,你怎…...
带参宏定义
#define WM_EVENT_DECLARE_GROUP(group) extern wm_event_group_t const group 宏定义的结构: #define:这是C语言中的预处理指令,用来定义宏。宏的作用是替换代码中的特定部分,类似于全局的文本替换。这里定义的宏名称是 WM_EVE…...
java流
99. ByteArrayOutputStream转化为ByteArrayInputStream ByteArrayOutputStream baos xxx;i new ByteArrayInputStream(baos.toByteArray())100.将inputstream转换为byte[] https://blog.csdn.net/yogima/article/details/128500056 100.1 方式一 直接使用IOUtils byte[] …...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
Python爬虫实战:研究Restkit库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...
云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...
【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理:检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目:RankRAG:Unifying Context Ranking…...
Git 命令全流程总结
以下是从初始化到版本控制、查看记录、撤回操作的 Git 命令全流程总结,按操作场景分类整理: 一、初始化与基础操作 操作命令初始化仓库git init添加所有文件到暂存区git add .提交到本地仓库git commit -m "提交描述"首次提交需配置身份git c…...
