QtCreator源码分析 -3.插件管理系统

来源:互联网 发布:mac怎么创建文件夹 编辑:程序博客网 时间:2024/06/05 04:07

首先,我们先看看QT的插件系统。

QT的插件模型类似于在COM本质论前面部分内容里描述的模型(不过还没有去看具体的源码,实现机制是否一样还不确定)。动态链接库通过继承一个简单接口的纯虚类,在需要的时候动态载入,然后通过纯虚类的接口函数进行进一步的访问。从而为动态链接库提供一个统一的发现方式。

 

在QT的插件系统中,提供给对外使用的主要有IPlugin、PluginManager、PluginSpec这三个类,PluginView、PluginErrorView、PluginDetailsView三个辅助类。我们主要研究三个主要类IPlugin、PluginManager、PluginSpec。这三个类的具体实现由IPluginPrivate、PluginManagerPrivate、PluginSpecPrivate三个类实现,目的是对外屏蔽实现的具体细节。

 

1、IPlugin,IPluginPrivate 插件接口类

IPlugin类为插件的接口类(纯虚类),其作用是为动态链接库导出类提供统一的发现接口,从而达到插件的目的。

image

每个插件都需要至少提供initialize(const QStringList &arguments, QString *errorString)和extensionsInitialized()两个函数,为插件类提供初始化功能。

其中addObject、addAutoReleasedObject、removeObject三个函数为插件类的实例化提供计数功能。

2、PluginSpec、PluginSpecPrivate 插件说明类

插件说明类以插件的说明信息提供服务,包括名字、版本、位置、依赖关系,参数、状态等等。

image

 

3、PluginManager、PluginManagerPrivate 插件管理类

插件管理类提供对插件的管理功能,为我们这次主要研究的类。

image 

PluginManager类对外提供的函数主要分为三类:对象池操作、插件操作、和对于参数的操作。

对于对象池的操作有addObject()添加对象、removeObject()移除对象、allObjects()获取所有对象、getObjects()获取某个类的所有对象、getObject()获取某个类的第一个对象。在getObjects()和getObject()中使用了Aggregation类的查询操作。并且在对象添加和移除后引发objectAdded和aboutToRemoveObject信号。

对于插件的操作主要有loadPlugins()载入插件、setPluginPaths()、pluginPaths()设置和获取插件路径、plugins()获取插件配置列表、setFileExtension()、fileExtension设置插件配置文件的类型。关于插件的操作是需要主要分析的对象,我按照在主程序中的操作依序分析相关的函数。

3.1、void setFileExtension(const QString &extension)         设置插件配置文件类型

void PluginManager::setFileExtension(const QString &extension){    d->extension = extension;}
仅仅对细节实现类的extension插件配置文件类型属性进行了赋值。
3.2、void setPluginPaths(const QStringList &paths)   设置插件路径列表
void PluginManager::setPluginPaths(const QStringList &paths){    d->setPluginPaths(paths);}
void PluginManagerPrivate::setPluginPaths(const QStringList &paths){    pluginPaths = paths;    readPluginPaths();}
void PluginManagerPrivate::readPluginPaths(){    qDeleteAll(pluginSpecs);    pluginSpecs.clear();    QStringList specFiles;    QStringList searchPaths = pluginPaths;    while (!searchPaths.isEmpty()) {   //找出所有的插件配置文件        const QDir dir(searchPaths.takeFirst());       const QFileInfoList files = dir.entryInfoList(QStringList() << QString("*.%1").arg(extension), QDir::Files); //后缀名为extension定义的文件        foreach (const QFileInfo &file, files)            specFiles << file.absoluteFilePath();       const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);       foreach (const QFileInfo &subdir, dirs)            searchPaths << subdir.absoluteFilePath(); //添加当前文件夹的子文件夹    }    foreach (const QString &specFile, specFiles) {       PluginSpec *spec = new PluginSpec;       spec->d->read(specFile);  //读取配置文件        pluginSpecs.append(spec);  //添加到配置列表    }    resolveDependencies();  //解析依赖关系    // ensure deterministic plugin load order by sorting    qSort(pluginSpecs.begin(), pluginSpecs.end(), lessThanByPluginName); //按字母从小到大排序    emit q->pluginsChanged();}

可以看出在设置插件路径的函数中,首先找出了所有的插件的配置文件,再添加到配置列表中,然后再解析其依赖关系。

在解析其依赖关系的函数中bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs),会检查每个所依赖的所有的项目,如果有项目不存在,则会报错。

3.3、pluginManager.parseOptions(arguments, appOptions, &foundAppOptions, &errorMessage)解析启动参数

bool PluginManager::parseOptions(const QStringList &args,    const QMap<QString, bool> &appOptions,    QMap<QString, QString> *foundAppOptions,    QString *errorString){    OptionsParser options(args, appOptions, foundAppOptions, errorString, d);    return options.parse();}

OptionsParser 类解析具体的参数,并将对于各个插件的参数填入插件配置类的信息中。

3.4、pluginManager.loadPlugins() 载入插件

void PluginManagerPrivate::loadPlugins(){    QList<PluginSpec *> queue = loadQueue();    foreach (PluginSpec *spec, queue) {        loadPlugin(spec, PluginSpec::Loaded); //载入插件    }    foreach (PluginSpec *spec, queue) {        loadPlugin(spec, PluginSpec::Initialized); //初始化插件    }    QListIterator<PluginSpec *> it(queue);    it.toBack();    while (it.hasPrevious()) {        loadPlugin(it.previous(), PluginSpec::Running);//运行插件    }    emit q->pluginsChanged();}
void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState){    if (spec->hasError())        return;    if (destState == PluginSpec::Running) {        spec->d->initializeExtensions();  //运行插件        return;    } else if (destState == PluginSpec::Deleted) {        spec->d->kill();        return;    }    //检查插件的依赖项    foreach (PluginSpec *depSpec, spec->dependencySpecs()) {        if (depSpec->state() != destState) {            spec->d->hasError = true;            spec->d->errorString =                PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)/nReason: %3")                    .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString());            return;        }    }    if (destState == PluginSpec::Loaded)        spec->d->loadLibrary();    else if (destState == PluginSpec::Initialized)        spec->d->initializePlugin();    else if (destState == PluginSpec::Stopped)        spec->d->stop();}
对插件执行了加载、初始化、运行三个操作。对这三个操作具体分析。
加载:
bool PluginSpecPrivate::loadLibrary(){    //一些检查和插件的动态链接库的名字的形成    ....    PluginLoader loader(libName);    if (!loader.load()) {        ....   
    }    //插件载入得到插件接口类    IPlugin *pluginObject = qobject_cast<IPlugin*>(loader.instance());   if (!pluginObject) {        ....    
   }   state = PluginSpec::Loaded;   plugin = pluginObject;   plugin->d->pluginSpec = q; //设置插件的配置文档   return true;}
初始化:
bool PluginSpecPrivate::initializePlugin(){    ....//一些检查    if (!plugin->initialize(arguments, &err)) {//带参数的初始化        ...   }   state = PluginSpec::Initialized;   return true;}
其中插件接口类的initialize函数为纯虚函数,由每个具体的接口实现。
运行:
bool PluginSpecPrivate::initializeExtensions(){    ...//一些检查    if (!plugin) {...    }    plugin->extensionsInitialized(); //运行    state = PluginSpec::Running;    return true;}

其中插件接口类的extensionsInitialized函数为纯虚函数,由每个具体的接口实现。

原创粉丝点击