当前位置: 首页 > news >正文

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服务追踪是一种机制&#xff0c;用于在CTK插件框架中追踪和管理插件提供的服务。当一个插件注册了一个服务到服务注册中心后&#xff0…...

[针对于个人用户] 显卡与计算卡性能对比表

笔者使用 Quadro M4000 显卡用于 LLM 相关任务&#xff0c;但奈何该卡发布的年代过于久远&#xff0c;以至于 LLM 相关任务只能使用例如&#xff1a;Phi3 mini、Qwen 2 2B、GLM 4 8B 以及 Gemini v2 2B等小参数模型&#xff0c;且速度不堪理想&#xff0c;也经常因为显卡过热降…...

2024年智能录屏解决方案全攻略,从桌面到云端

如果你有过录屏经验那你一定遇到过被限制录制时长或者录制的画面比较模糊之类的情况。这次我我推荐几款免费录屏软件&#xff0c;让我们可以更自由的录制屏幕画面。 1.福晰REC大师 链接&#xff1a;www.foxitsoftware.cn/REC/ 这款软件便捷好操作&#xff0c;而且符合我这次…...

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…...

水库大坝安全监测方案,双重守护,安全无忧

水库作为重要的水利设施&#xff0c;在防洪、灌溉及供水等方面发挥着重要作用。然而随着时间的推移&#xff0c;大坝面临着自然老化、设计标准不足及极端天气等多重挑战&#xff0c;其安全性与稳定性日益受到关注。水库堤坝险情导致的洪涝灾害给人民生命财产和经济社会发展带来…...

yolov8实现图片验证码识别

1、环境准备 1.1、安装miniconda 地址&#xff1a;Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 注意&#xff1a;为避免不兼容的问题&#xff0c;推荐下载py38版本&#xff0c;我下载的是Miniconda3-py38_23.1.0-1-Windows-x86_…...

代码随想录训练营 Day56打卡 图论part06 108. 冗余连接 109. 冗余连接II

代码随想录训练营 Day56打卡 图论part06 一、卡码108. 冗余连接 题目描述 有一个图&#xff0c;它是一棵树&#xff0c;他是拥有 n 个节点&#xff08;节点编号1到n&#xff09;和 n - 1 条边的连通无环无向图&#xff08;其实就是一个线形图&#xff09;&#xff0c;如图&…...

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 项目**&#xff1a;**添加 Servlet 依赖**&#xff1a;**创建 Servlet 类**&#xff1a;**配置项目**&#xff1a;**配置 Tomcat**&#xff1a; 1.2. 路由机制1.3. 示例代…...

React的事件与原生事件的执行顺序?

react自身实现了一套自己的事件机制&#xff0c;包括事件注册、事件的合成、事件冒泡、事件派发等&#xff0c;虽然和原生的是两码事&#xff0c;但也是基于浏览器的事件机制下完成的。 react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上&#xff0c;然后由…...

【Java】Runtime与Properties获取系统信息

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述四、解决方案&#xff1a;4.1 代码4.2 运行结果 五、总结&#xff1a; 一、前言 这些都被淘汰比较少用了…...

基于SpringBoot的社团管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、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)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 轻内核A核源码分析系列一 数据结构-双向循环链表 轻内核A核源码分析系列二 数据结构-位图操作 轻内核A核源码分析系列三 物理内存&#xff08;1&#xff0…...

qt QGraphicsScene场景坐标和场景内GraphicsItem局部坐标的相互转换

为了更清晰地解释场景坐标与局部坐标之间的转换过程&#xff0c;我们可以通过一个简单的实例来演示如何赋值场景坐标&#xff0c;并将其转换为图形项的局部坐标。 实例步骤 假设我们有一个场景 QGraphicsScene 和一个矩形图形项 QGraphicsRectItem&#xff0c;矩形的大小为 1…...

Windows与linux中docker的安装与使用

windos中安装使用docker 下载Docker_Desktop 安装包进入docker官网下载Docker_Desktop&#xff1a; https://www.docker.com/启用wsl 我们搜索“启用或关闭Windows功能”&#xff0c;打开后勾选适用于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

沟通&#xff1a; 想明⽩&#xff0c;说清楚&#xff0c;能接受 团队沟通的正确⽅式可以⽤9个字来概括&#xff1a;想明⽩&#xff0c;说清楚&#xff0c;能接受 &#xff08;⻅图4-1&#xff09;想明⽩ 有时经理跟⼈沟通&#xff0c;讲完之后却⽆奈地对员⼯说&#xff0c;你怎…...

带参宏定义

#define WM_EVENT_DECLARE_GROUP(group) extern wm_event_group_t const group 宏定义的结构&#xff1a; #define&#xff1a;这是C语言中的预处理指令&#xff0c;用来定义宏。宏的作用是替换代码中的特定部分&#xff0c;类似于全局的文本替换。这里定义的宏名称是 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[] …...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...