【Qt】通过QtCreator源码学习Qt(八):插件生命周期及对应状态(代码走读)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010168781/article/details/84892481
1、简介

PluginManager管理插件IPlugin的生命周期,从初始化插件到删除插件共八个状态。插件状态表——PluginSpec::enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted};
插件IPlugin的状态记录在与插件对应的插件说明PluginSpec中,状态切换过程如下:

  • 当new PluginSpec时,还没有插件与之关联,此时PluginSpec记录的插件状态为无效(Invalid);
  • 读取插件文件后,状态切换成已读(Read);
  • 读取全部插件后,首先需要解决插件之间的依赖问题,解决完毕后,状态切换成已解决(Resolved);
  • 然后安装依赖顺序依次加载插件,状态切换成已加载(Loaded);
  • 初始化所有插件,状态切换成已初始化(Initialized);
  • 运行插件,状态切换成正在运行(Running);
  • 当QtCreator退出时,插件依次退出,状态切换成(Stopped);
  • 全部退出后,删除插件,状态切换成(Deleted)。
2、状态管理器PluginManager的初始化

初始化、设置IID、设置settings

PluginManager pluginManager;
PluginManager::setPluginIID(QLatin1String("org.qt-project.Qt.QtCreatorPlugin"));
PluginManager::setGlobalSettings(globalSettings);
PluginManager::setSettings(settings);

设置插件路径列表,插件所在目录:Qt5.*/Tools/QtCreator/lib/qtcreator/plugins,
程序中使用的是该目录相对Qt5.6.3/Tools/QtCreator/bin的路径。

pluginPaths = QApplication::applicationDirPath() + '/' + RELATIVE_PLUGIN_PATH
PluginManager::setPluginPaths(pluginPaths);
3、插件生命周期详解

在PluginManager::setPluginPaths(pluginPaths);中完成插件由“无效状态”到“已读状态”再到“解决依赖状态”的转变,详细过程如下:
【1】PluginManager遍历插件路径,并创建插件说明PluginSpec,此时插件状态为初始值:【Invalid】;
(PluginManager::setPluginPaths(pluginPaths) --> readPluginPaths() --> foreach{PluginSpec *spec = new PluginSpec} --> PluginSpec::State state = PluginSpec::Invalid)

【2】在PluginSpec读取插件文件中的元信息QPluginLoader::metaData()(元信息类型QJsonObject)后,插件状态由【Invalid】变成【Read】;
(PluginManager::setPluginPaths(pluginPaths) --> readPluginPaths() --> foreach{spec->d->read(pluginFile)} --> loader.setFileName(filePath) --> readMetaData(loader.metaData()))

【3】读取所有插件文件后,需要解决插件之间的依赖关系和顺序,处理完毕后插件状态由【Read】变成【Resolved】
(PluginManager::setPluginPaths(pluginPaths) --> readPluginPaths() --> resolveDependencies() --> foreach{spec->d->resolveDependencies(pluginSpecs)});

在PluginManager::loadPlugins();中完成插件由“加载状态”到“初始化状态”再到“运行状态”的转变,详细过程如下:

【4】loadPlugins中遍历插件说明PluginSpec,并执行QPluginLoader::load(),插件状态由【Resolved】变成【Loaded】
(foreach{loadPlugin(spec, PluginSpec::Loaded)} --> spec->d->loadLibrary() --> loader.load());

【5】loadPlugins中遍历插件说明PluginSpec,并执行IPlugin::initialize(arguments, &err),插件状态由【Loaded】变成【Initialized】
(foreach{loadPlugin(spec, PluginSpec::Initialized)} --> spec->d->initializePlugin() --> plugin->initialize(arguments, &err));

【6】loadPlugins中反向遍历插件说明PluginSpec,并执行IPlugin::extensionsInitialized(),插件状态由【Initialized】变成【Running】
(Utils::reverseForeach{loadPlugin(spec, PluginSpec::Initialized)} --> spec->d->initializeExtensions() --> plugin->extensionsInitialized());

插件在收到QtCreator发出的退出信号后,执行退出操作。
QObject::connect(&app, &QCoreApplication::aboutToQuit, &pluginManager, &PluginManager::shutdown);

【7】当程序退出时,发出信号QCoreApplication::aboutToQuit,执行槽函数PluginManager::shutdown;
遍历插件说明PluginSpec,并将状态由【Running】变成【Stopped】然后执行IPlugin::aboutToShutdown();
为了等待插件退出,执行shutdownEventLoop->exec(),当所有插件退出后,再继续往下运行;
当插件IPlugin准备好退出时,会发送信号IPlugin::asynchronousShutdownFinished(),通知槽函数PluginManagerPrivate::asyncShutdownFinished()执行;
当所有的插件都发来信号后,调用shutdownEventLoop->exit(),退出事件循环,继续往下运行。
(PluginManager::shutdown --> stopAll() --> foreach{loadPlugin(spec, PluginSpec::Stopped)} --> spec->d->stop() --> plugin->aboutToShutdown())

【8】当所有的插件都停止并退出后,反向遍历插件说明PluginSpec,并删除插件delete IPlugin,插件状态由【Stopped】变成【Deleted】
(PluginManager::shutdown --> deleteAll() --> Utils::reverseForeach{loadPlugin(spec, PluginSpec::Deleted)} --> spec->d->kill() --> delete plugin)

猜你喜欢

转载自blog.csdn.net/u010168781/article/details/84892481