目录
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框架(四): 插件编写里面介绍了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_OBJECT
Q_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_OBJECT
Q_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插件框架中一个重要的功能,它允许开发者追踪和管理插件提供的服务。通过服务追踪机制,插件可以更容易地获取和使用其他插件提供的服务,从而提高系统的灵活性和可扩展性。在实际开发中,开发者可以根据需要创建自定义的服务追踪器来实现对特定服务的追踪和管理。