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[] …...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
