CTK 插件之间的依赖
简述
插件是 CTK 中的基础元件,不同的插件之间可以相互依赖、引用,这样许多插件才会共同协作,实现一些比较复杂的功能。 但是,在处理插件依赖的同时,也面临着一个极具挑战性的问题 - 如何保证每个插件都能加载成功?
版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820 CTK 中的插件依赖在 CTK 中的 MANIFEST.MF 文件 中,我们介绍过 CTK 本身提供了一些清单头。其中
假设,存在 A、B 两个插件,B 依赖 A(即:B 离不开 A)。那么,在插件加载过程中,可能会存在以下情况:
依赖验证为了测试上述情景,写一个简单的管理类来加载插件: // 指定加载顺序
bool Manager::loadAllPlugins(const QString &path)
{
QString strDll = path + "/plugin_a.dll";
bool isALoaded = loadPlugin(strDll);
strDll = path + "/plugin_b.dll";
bool isBLoaded = loadPlugin(strDll);
return (isALoaded && isBLoaded);
}
// 加载插件
bool Manager::loadPlugin(const QString &path)
{
ctkPluginContext* context = framework->getPluginContext();
try {
QUrl location = QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath());
QSharedPointer<ctkPlugin> plugin = context->installPlugin(location);
plugin->start(ctkPlugin::START_TRANSIENT);
} catch(const ctkPluginException &e) {
qDebug() << QString("Failed to install plugin") << e.what();
return false;
}
return true;
}
在测试时,注意调换插件 A、B 的加载顺序。除此之外,还需要修改插件 B 中的 MANIFEST.MF 文件(弱依赖用 Require-Plugin: plugin.a; resolution:="mandatory"
经过反复测试,暂时可以得出以下结论:
看似有这么一点意思:弱依赖,有没有你都无所谓;强依赖,必须有你,而且你还得比别人提前。 异常的引发在使用
这时因为在调用 void ctkPluginFrameworkContext::checkRequirePlugin(ctkPluginPrivate *plugin)
{
// ...
if (!ok && pr->resolution == ctkPluginConstants::RESOLUTION_MANDATORY)
{
tempResolved.clear();
if (debug.resolve)
{
qDebug() << "checkRequirePlugin: failed to satisfy:" << pr->name;
}
throw ctkPluginException(QString("Failed to resolve required plugin: %1").arg(pr->name));
}
// ...
}
当所依赖的插件没有被解析时,就会抛出异常。 那么,倘若插件之间存在强依赖关系,又不想以硬编码的形式指定加载顺序怎么办? 解决依赖关系看来,现在的所有问题都集中在一点上:如何保证插件的加载顺序? 若要自己实现一个加载顺序,就必须知道插件所依赖的其他插件。而这些信息可以由 MANIFEST.MF 文件获得,但是要读取这些信息又必须加载插件,这似乎陷入了一个死循环:
通过 CTK 文档,可以发现 MANIFEST.MF 文件的信息其实在安装插件后就可以获取到,也就是 // 加载所有插件
bool Manager::loadAllPlugins(const QString &path)
{
// 安装所有插件
QDirIterator itPlugin(path,QStringList() << "*.para",QDir::Files);
while (itPlugin.hasNext()) {
QString pluginPath = itPlugin.next();
if (!installPlugin(pluginPath))
return false;
}
// 自己实现一个加载规则(按顺序加载:A -> B -> C)
ctkPluginContext* context = framework->getPluginContext();
QList<QSharedPointer<ctkPlugin> > plugins = context->getPlugins();
foreach (QSharedPointer<ctkPlugin> plugin,plugins) {
QHash<QString,QString> headers = plugin->getHeaders();
// 获取 Require-Plugin 的信息
// 可以递归获取各个插件所依赖的插件,形成一条加载链
}
return true;
}
看似没太大问题,但再深入思考一下,存在以下几个问题:
好不容易发现一条新路,又被堵死了。。。通过循环依赖,可以看出指定插件加载顺序貌似就是一个错误。 最终,通过源码可以发现,在执行 // 加载所有插件
bool Manager::loadAllPlugins(const QString &path)
{
// 安装所有插件
QDirIterator itPlugin(path,QStringList() << "*.dll",QDir::Files);
while (itPlugin.hasNext()) {
QString pluginPath = itPlugin.next();
if (!installPlugin(pluginPath))
return false;
}
// 启动所有插件
ctkPluginContext* context = framework->getPluginContext();
QList<QSharedPointer<ctkPlugin> > plugins = context->getPlugins();
foreach (QSharedPointer<ctkPlugin> plugin,plugins) {
if (!startPlugin(plugin))
return false;
}
return true;
}
// 安装插件
bool Manager::installPlugin(const QString &path)
{
ctkPluginContext* context = framework->getPluginContext();
try {
QUrl location = QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath());
QSharedPointer<ctkPlugin> plugin = context->installPlugin(location);
} catch(const ctkPluginException &e) {
qDebug() << QString("Failed to install plugin") << e.what();
return false;
}
return true;
}
// 启动插件
bool Manager::startPlugin(QSharedPointer<ctkPlugin> plugin)
{
try {
plugin->start(ctkPlugin::START_TRANSIENT);
} catch(const ctkPluginException &e) {
qDebug() << QString("Failed to start plugin") << e.what();
return false;
}
return true;
}
这时,即使存在强依赖也不出现任何问题,这是因为所有的插件已经被优先安装了(包括它所依赖的插件)。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |