一、前言

在本系列文章:Qt插件开发总结3–插件间通信 一文中详细讲解了,插件-插件通信、插件-主程序通信。

但是这样虽然实现了通信,但是存在一定的弊端,之前的通信结构如下所示:

Qt插件开发总结7--插件通信升级【多线程通信】_加载


插件和主程序都必须依靠【插件管理器】作为中转站,来相互通信。如果一旦通信比较密集,那么插件管理器肯定负载跟不上,那通信的效率就会变得很慢,可以理解这是半双工通信,即同一时刻,只能有一个人在收或发。

为此,我们必须改变现有结构,来实现更高效率的通信。


二、方案

之前的通信转发都是在插件管理器的槽函数中,通信体量变大,消息肯定会在这堵塞。

所以我引入线程池,将消息转发功能,打包为线程池任务。

不熟悉线程池的朋友,可以查看我的这篇博客:Qt线程池

消息一到槽函数中,槽函数不做任何处理,直接将其打包并丢入线程池中,线程池自动分配线程来执行任务。这样就变成多窗口同步作业。

Qt插件开发总结7--插件通信升级【多线程通信】_加载_02


如上图所示,插件或主程序只需要释放信号,信号响应插件管理器的槽函数,槽函数打包线程池任务,线程池子线程执行任务,完成消息转发。

Qt插件开发总结7--插件通信升级【多线程通信】_开发语言_03


Qt插件开发总结7--插件通信升级【多线程通信】_#include_04


三、效果展示

Qt插件开发总结7--插件通信升级【多线程通信】_#include_05


四、关键代码

4.1、主程序

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include "PluginManager.h"
#include <QDir>
#include <QMenuBar>
#include <QToolBar>
#include <QTabWidget>
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>

#include "./Widget/speeddashbroad.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void Init_UI();

    void recvMsgFromManager(PluginMetaData metaData);

public:
    QMenuBar* menuBar;
    QMenu* menuFile;
    QMenu* menuEdit;
    QMenu* menuView;
    QMenu* menuTool;

    QTabWidget* tabWidget;

public:
    SpeedDashBroad* sdb;

signals:
    void sendMsgToManager(PluginMetaData);

private slots:
    void slot_PluginAction_MenuBar(QString menu,QStringList actionList);    //添加插件菜单栏Action
    void slot_PluginsAction_trigger(bool isChecked);    //响应插件Action

    void slot_PluginWidget(QPluginLoader*,QString);    //添加插件widget


private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    Init_UI();

    //传递主程序指针给插件管理器
    PluginManager::instance()->m_mainWin = this;
    //绑定主程序和插件管理器消息信号槽
    connect(this,&MainWindow::sendMsgToManager,PluginManager::instance(),&PluginManager::recMsgFromPlugin);

    //嗅探到的所有插件
    qDebug()<<"嗅探插件: "<<PluginManager::instance()->CK_allPluginsName().keys();

    //加载所有插件
    foreach(QString pluginName , PluginManager::instance()->CK_allPluginsName().keys()) {
        PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value(pluginName));
    }

    //加载所有插件
//    PluginManager::instance()->loadAllPlugins();

    //加载存在依赖稍候处理的插件
    while(!PluginManager::instance()->m_remainPlugin.isEmpty()) {
        QString plugin_filePath = PluginManager::instance()->m_remainPlugin.pop();
        //qDebug()<<endl<<endl<<"加载存在依赖稍候处理的插件: "<<plugin_filePath;

        PluginManager::instance()->loadPlugin(plugin_filePath);
    }

    //加载其中某个插件
//    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginA"));
//    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginB"));
//    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginC"));
//    PluginManager::instance()->loadPlugin(PluginManager::instance()->CK_allPluginsName().value("pluginD"));

//    QPluginLoader *loader1 = PluginManager::instance()->getPlugin("pluginA");
//    PluginInterface* pluginInterface1 = qobject_cast<PluginInterface *>(loader1->instance());
//    pluginInterface1->showSomeThing("新增接口API");

//    QPluginLoader *loader2 = PluginManager::instance()->getPlugin("pluginB");
//    PluginInterface* pluginInterface2 = qobject_cast<PluginInterface *>(loader2->instance());
//    pluginInterface2->showSomeThing("新增接口API");

    //通信测试
    //================================================================================
    QPluginLoader *loader1 = PluginManager::instance()->getPlugin("pluginA");
    if(loader1) {
        PluginInterface *pluginA = dynamic_cast<PluginInterface*>(loader1->instance());
        if(pluginA) {
            PluginMetaData m;
            m.dest = "pluginB";
            m.from = "pluginA";
            m.msg = "插件A发给插件B的消息";
            pluginA->sendMsgToManager(m);
        }
    }

    QPluginLoader *loader2 = PluginManager::instance()->getPlugin("pluginB");
    if(loader2) {
        PluginInterface *pluginB = dynamic_cast<PluginInterface*>(loader2->instance());
        if(pluginB) {
            PluginMetaData m;
            m.dest = "pluginA";
            m.from = "pluginB";
            m.msg = "插件B发给插件A的消息";
            pluginB->sendMsgToManager(m);
        }
    }

    //------------------------------
    if(loader2) {
        PluginInterface *pluginB = dynamic_cast<PluginInterface*>(loader2->instance());
        if(pluginB) {
            PluginMetaData m1;
            m1.dest = "mainWin";
            m1.from = "pluginB";
            m1.msg = "插件B发给主程序的消息";
            pluginB->sendMsgToManager(m1);
        }
    }

    //------------------------------
    PluginMetaData m2;
    m2.dest = "pluginA";
    m2.from = "mainWin";
    m2.msg = "主程序发给插件A的消息";
    this->sendMsgToManager(m2);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::Init_UI()
{
    QWidget* p = takeCentralWidget();   //删除中央窗体
    if (p) {
        delete p;
    }
    setDockNestingEnabled(true);        //允许嵌套dock

    //-------------------------------------------------

    menuBar = new QMenuBar(this);

    menuFile = new QMenu("文件", this);
    menuBar->addMenu(menuFile);
    this->setMenuBar(menuBar);

    menuEdit = new QMenu("编辑", this);
    menuBar->addMenu(menuEdit);
    this->setMenuBar(menuBar);

    menuView = new QMenu("视图", this);
    menuBar->addMenu(menuView);
    this->setMenuBar(menuBar);

    menuTool = new QMenu("工具", this);
    menuBar->addMenu(menuTool);
    this->setMenuBar(menuBar);

    connect(PluginManager::instance(),&PluginManager::sig_actions,this,&MainWindow::slot_PluginAction_MenuBar);

    //-------------------------------------------------

    tabWidget = new QTabWidget(this);
    tabWidget->setMinimumSize(1000, 800);   // 设置最小宽高
    setCentralWidget(tabWidget);            // 指定为中心窗口

    connect(PluginManager::instance(),&PluginManager::sig_widget,this,&MainWindow::slot_PluginWidget);

    //-------------------------------------------------

    sdb = new SpeedDashBroad;
    tabWidget->addTab(sdb,"表盘");
}

void MainWindow::slot_PluginAction_MenuBar(QString menu,QStringList actionList)
{
    QAction * action = nullptr;
    if(menu == QString::fromLocal8Bit("menuFile")) {
        for(int i=0; i<actionList.size(); ++i) {
            action = new QAction(QIcon(), actionList.at(i), this);
            menuFile->addAction(action);
            connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
        }
    }
    if(menu == QString::fromLocal8Bit("menuEdit")) {
        for(int i=0; i<actionList.size(); ++i) {
            action = new QAction(QIcon(), actionList.at(i), this);
            menuEdit->addAction(action);
            connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
        }
    }
    if(menu == QString::fromLocal8Bit("menuView")) {
        for(int i=0; i<actionList.size(); ++i) {
            action = new QAction(QIcon(), actionList.at(i), this);
            menuView->addAction(action);
            connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
        }
    }
    if(menu == QString::fromLocal8Bit("menuTool")) {
        for(int i=0; i<actionList.size(); ++i) {
            action = new QAction(QIcon(), actionList.at(i), this);
            menuTool->addAction(action);
            connect(action,&QAction::triggered,this,&MainWindow::slot_PluginsAction_trigger);
        }
    }
}

void MainWindow::recvMsgFromManager(PluginMetaData metaData)
{
    qDebug()<<"主程序接收到消息:"<<metaData.msg;
}

void MainWindow::slot_PluginsAction_trigger(bool isChecked)
{
    QAction* action = qobject_cast<QAction*>(sender());
    for(int i=0; i<PluginManager::instance()->_actionMap.size(); ++i) { //遍历插件管理器action映射表
        if(PluginManager::instance()->_actionMap.at(i).action == action->text()) {  //映射表中匹配到Action对应的方法
            PluginInterface* plugin = qobject_cast<PluginInterface *>(PluginManager::instance()->_actionMap.at(i).plugin->instance());  //获取该action对应的接口指针
            if(plugin) {
                for(int j=0; j<plugin->_actionName.size(); ++j) {   //遍历该接口指针内的action名字
                    if(plugin->_actionName[j] == action->text()) {
                        plugin->_actionFunction[j](true);
                        break;
                    }
                }
            }
            break;
        }
    }
}

void MainWindow::slot_PluginWidget(QPluginLoader* loader,QString widget)
{
    if(widget == QString::fromLocal8Bit("tabWidget")) {
        PluginInterface* pluginInterface = qobject_cast<PluginInterface *>(loader->instance());
        QString pluginName = pluginInterface->_Plugin_Name;
        QWidget* widget = pluginInterface->_widget;

        if(widget) {
            tabWidget->addTab(widget,pluginName);
        }
    }

    //也可以预留布局接入点,插件UI嵌入,看自己需求
    if(widget == QString::fromLocal8Bit("xxxLayout")) {

    }

}

4.2、插件管理器

#ifndef PLUGINMANAGER_H
#define PLUGINMANAGER_H

#include "../Plugin_Interface/PluginInterface.h"
#include <QObject>
#include <QPluginLoader>
#include <QVariant>
#include <QAction>
#include <QStack>

#include <QThread>
#include <QThreadPool>

class MainWindow;
class TransMessageRunable;

typedef struct manager_action_map
{
    QString action;
    QPluginLoader* plugin;
}MANAGER_ACTION_MAP;

class PluginManager : public QObject
{
    Q_OBJECT
public:
    explicit PluginManager(QObject *parent = nullptr);
    ~PluginManager();

    static PluginManager *instance(){
         if(m_instance==nullptr)
             m_instance=new PluginManager();
         return m_instance;
     }

public:
    MainWindow* m_mainWin;  //主程序指针

    QStack<QString> m_remainPlugin; //存在依赖待处理插件栈

public:
    QList<MANAGER_ACTION_MAP> _actionMap;
    void deal_metaData(QPluginLoader* loader,QJsonObject& json);

public:
    //扫描JSON文件中的插件元数据
    void scanMetaData(const QString &filepath,QJsonObject& json);

     //加载所有插件
     void loadAllPlugins();

     //加载其中某个插件
     void loadPlugin(const QString &filepath);

     //卸载所有插件
     void unloadAllPlugins();

     //卸载某个插件
     void unloadPlugin(const QString &filepath);

     //获取所有插件名称
     QList<QVariant> allPluginsName();

     //获取所有插件
     QList<QPluginLoader *> allPlugins();

     //获取某个插件名称
     QVariant getPluginName(QPluginLoader *loader);

     //根据名称获得插件
     QPluginLoader* getPlugin(const QString &name);

     //获取库中所有插件名称
     QHash<QString,QString> CK_allPluginsName();

signals:
     void sig_actions(QString,QStringList);
     void sig_widget(QPluginLoader*,QString);

public slots:
     void recMsgFromPlugin(PluginMetaData);

     void slot_test();

private:
     static PluginManager *m_instance;

     class PluginsManagerPrivate;
     PluginsManagerPrivate *managerPrivate;

     TransMessageRunable* m_transMessageRunable;

};

#endif // PLUGINMANAGER_H
#include "PluginManager.h"
#include "mainwindow.h"
#include "TransMessageRunable.h"

#include <QDir>
#include <QCoreApplication>
#include <QJsonArray>
#include <QDebug>

PluginManager* PluginManager::m_instance=nullptr;

class PluginManager::PluginsManagerPrivate
{
public:
    PluginsManagerPrivate()
    {
        m_names.clear();
        m_versions.clear();
        m_dependencies.clear();
        m_loaders.clear();

        m_dependencies_temp.clear();
    }
    ~PluginsManagerPrivate(){}

    QHash<QString, QVariant> m_names;               //插件路径--插件名称
    QHash<QString, QVariant> m_versions;            //插件路径--插件版本
    QHash<QString, QVariantList> m_dependencies;    //插件路径--插件额外依赖的其他插件
    QHash<QString, QPluginLoader *> m_loaders;      //插件路径--QPluginLoader实例

    QHash<QString, QVariantList> m_dependencies_temp;

    bool check(const QString &filepath)             //插件依赖检测
    {
        //qDebug()<<QString("=============== bool check(%1) ===============").arg(filepath);
        bool status = true;

        foreach (QVariant item, m_dependencies_temp.value(filepath)) {
            QString dependencyPluginInfo = item.toString();
            // 依赖的插件名称、版本、路径
            QStringList List = dependencyPluginInfo.split(':');
            QString name_str = List[0];
            QString version_str = List[1];
            QString path = m_names.key(name_str);

//            qDebug()<<"=== 插件依赖信息 ===";
//            qDebug()<<"name_str: "<<name_str;
//            qDebug()<<"version_str: "<<version_str;
//            qDebug()<<"path: "<<path;

            QVariant name = QVariant(name_str);
            QVariant version = QVariant(version_str);

            /********** 检测插件是否依赖于其他插件 **********/
            // 先检测插件名称
            if (!m_names.values().contains(name)) {
                //qDebug() << "=== 插件" << filepath <<"  缺少依赖插件:" << name.toString();
                status = false;
                continue;
            }

            // 再检测插件版本
            if (m_versions.value(path) != version) {
                //qDebug() << "=== 依赖插件: " << name.toString() << "当前版本为: " << m_versions.value(m_names.key(name)).toString() << "但是需要依赖插件版本为: " << version.toString();
                status = false;
                continue;
            }

            // 然后,检测被依赖的插件是否还依赖于另外的插件
            if (!check(path)) {
                //qDebug() << "=== 依赖插件:" << name.toString() << "又依赖: " << path;
                status = false;
                continue;
            }
        }


        //qDebug()<<"status: "<<status;
        return status;
    }

};

PluginManager::PluginManager(QObject *parent) : QObject(parent)
{
    managerPrivate = new PluginsManagerPrivate;

    //线程池
    //========================================================================
    //设置线程池最大线程数量
    QThreadPool::globalInstance()->setMaxThreadCount(10);

}
PluginManager::~PluginManager()
{
    delete managerPrivate;
}

void PluginManager::loadAllPlugins()
{
    QDir pluginsDir(qApp->applicationDirPath());    //pluginsDir: "../build-xxx-debug/debug"
    if(pluginsDir.dirName().toLower() == "debug" ||
            pluginsDir.dirName().toLower() == "release") {
        pluginsDir.cdUp();  //pluginsDir: "../build-xxx-debug"
        pluginsDir.cdUp();  //pluginsDir: "../"
    }
    pluginsDir.cd("plugins");

    QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);

    //加载插件
    for(QFileInfo fileinfo : pluginsInfo)
        loadPlugin(fileinfo.absoluteFilePath());
}

void PluginManager::scanMetaData(const QString &filepath,QJsonObject& json)
{
    //判断是否为库(后缀有效性)
    if(!QLibrary::isLibrary(filepath))
        return;

    if(managerPrivate->m_names.keys().contains(filepath)) {
        //qDebug()<<QString("插件: %1 已加载,退出!!!").arg(filepath);
        return;
    }

    //获取元数据
    QPluginLoader *loader = new QPluginLoader(filepath);

    //qDebug()<<loader->metaData().keys();
    json = loader->metaData().value("MetaData").toObject();
//    for(int i=0; i<json.keys().size(); ++i) {
//        qDebug()<<json.keys().at(i)<< " : "<<json.value(json.keys().at(i));
//    }

    managerPrivate->m_names.insert(filepath, json.value("name").toVariant());
    managerPrivate->m_versions.insert(filepath, json.value("version").toVariant());
    managerPrivate->m_dependencies.insert(filepath, json.value("dependencies").toArray().toVariantList());
    //qDebug()<<"dependencies: "<<json.value("dependencies").toArray().toVariantList();
    //qDebug()<<"managerPrivate->m_dependencies: "<<managerPrivate->m_dependencies.values();

    delete loader;
    loader = nullptr;
}

void PluginManager::loadPlugin(const QString &filepath)
{
    //库文件类型检测
    if(!QLibrary::isLibrary(filepath))
        return;

    //读取当前插件依赖
    //qDebug()<<"===========================================================================";
    QPluginLoader *loader_temp = new QPluginLoader(filepath);
    QJsonObject json_temp = loader_temp->metaData().value("MetaData").toObject();
    managerPrivate->m_dependencies_temp.insert(filepath, json_temp.value("dependencies").toArray().toVariantList());
    //qDebug()<<"managerPrivate->m_dependencies_temp: "<<managerPrivate->m_dependencies_temp;
    delete loader_temp;
    loader_temp = nullptr;

    //qDebug()<<"@@@ 当前加载插件: "<<filepath;

    //检测依赖
    if(!managerPrivate->check(filepath)) {
        //qDebug()<<"当前插件存在依赖,入栈,稍候处理: "<<filepath;
        m_remainPlugin.push(filepath);

        //清空当前插件依赖
        managerPrivate->m_dependencies_temp.clear();

        return;
    }

    //清空当前插件依赖
    managerPrivate->m_dependencies_temp.clear();

    //检测当前插件是否已加载
    if(managerPrivate->m_loaders.keys().contains(filepath)) {
        //qDebug()<<"当前插件已加载!!!";
        return;
    }

    //加载插件
    QPluginLoader *loader = new QPluginLoader(filepath);
    if(loader->load()) {
        PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
        if(plugin) {
            //检测元信息
            QJsonObject json;
            scanMetaData(filepath,json);
            deal_metaData(loader,json);

            managerPrivate->m_loaders.insert(filepath, loader);
            connect(loader->instance(),SIGNAL(sendMsgToManager(PluginMetaData)),
                    this,SLOT(recMsgFromPlugin(PluginMetaData)));

            //绑定
            if(plugin->_Plugin_Name == QString::fromLocal8Bit("PluginA")) {
                //qDebug()<<"plugin->_Plugin_Name: "<<plugin->_Plugin_Name;
                connect(loader->instance(),SIGNAL(sig_test()),
                        this,SLOT(slot_test()));
            }

            plugin->Info(QString(" %1 加载成功!").arg(plugin->_Plugin_Name));

        }else {
            delete loader;
            loader = nullptr;
        }
    }else{
        qDebug()<<"loadPlugin:"<<filepath<<loader->errorString();
    }
}

void PluginManager::unloadAllPlugins()
{
    for(QString filepath : managerPrivate->m_loaders.keys())
        unloadPlugin(filepath);
}

void PluginManager::unloadPlugin(const QString &filepath)
{
    if(!managerPrivate->m_loaders.keys().contains(filepath)) {
        return;
    }

    QPluginLoader *loader = managerPrivate->m_loaders.value(filepath);
    //卸载插件,并从内部数据结构中移除
    if(loader->unload()) {
        PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
        if(plugin) {
            plugin->Info("插件卸载成功!");
            managerPrivate->m_loaders.remove(filepath);
            delete loader;
            loader = nullptr;
        }
    }
}

QList<QPluginLoader *> PluginManager::allPlugins()
{
    return managerPrivate->m_loaders.values();
}

QList<QVariant> PluginManager::allPluginsName()
{
    return managerPrivate->m_names.values();
}

QVariant PluginManager::getPluginName(QPluginLoader *loader)
{
    if(loader)
        return managerPrivate->m_names.value(managerPrivate->m_loaders.key(loader));
    else
        return "";
}

QPluginLoader *PluginManager::getPlugin(const QString &name)
{
    return managerPrivate->m_loaders.value(managerPrivate->m_names.key(name));
}

void PluginManager::recMsgFromPlugin(PluginMetaData metaData)
{
    TransMessageRunable* task = new TransMessageRunable(metaData);
    task->setAutoDelete(true);  //autoDelete属性默认为true   QThreadPool会在run()函数运行结束后,自动删除了MyTask对象
    QThreadPool::globalInstance()->start(task); //任务放进线程池
    //QThread::sleep(1);
    //QThreadPool::globalInstance()->waitForDone(); //等待任务结束
}

void PluginManager::slot_test()
{
    //qDebug()<<"触发槽函数: PluginManager::slot_test()";
}

QHash<QString,QString> PluginManager::CK_allPluginsName()
{
    QDir pluginsDir(qApp->applicationDirPath());    //pluginsDir: "../build-xxx-debug/debug"
    if(pluginsDir.dirName().toLower() == "debug" ||
            pluginsDir.dirName().toLower() == "release") {
        pluginsDir.cdUp();  //pluginsDir: "../build-xxx-debug"
        pluginsDir.cdUp();  //pluginsDir: "../"
    }
    pluginsDir.cd("plugins");

    QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);

    //库中插件
    QHash<QString,QString> pluginNames;
    for(QFileInfo fileinfo : pluginsInfo){
        if(fileinfo.fileName().contains(".dll")) {
            QString pluginName = fileinfo.fileName().mid(0,fileinfo.fileName().size()-4);
            QString pluginPath = fileinfo.filePath();
            pluginNames.insert(pluginName,pluginPath);
        }
    }

    return pluginNames;
}

void PluginManager::deal_metaData(QPluginLoader* loader,QJsonObject& json)
{
    QString name;
    if(json.keys().contains("name")) {
        QJsonValue JValue = json.value("name").toString();
        name = JValue.toString();
    }
    //------------------------------------------------------------
    QString menu;
    QStringList actionList;
    if(json.keys().contains("menu")) {
        QJsonValue JValue = json.value("menu").toString();
        menu = JValue.toString();
    }
    if(json.keys().contains("action")) {
       QJsonArray JArray = json.value("action").toArray();
       for(int i=0;i<JArray.size();++i) {
           actionList << JArray.at(i).toString();

           MANAGER_ACTION_MAP manager_action_map;
           manager_action_map.action = JArray.at(i).toString();
           manager_action_map.plugin = loader;
           _actionMap.push_back(manager_action_map);
       }
    }

    QStringList dependencies_List;
    if(json.keys().contains("dependencies")) {
       QJsonArray JArray = json.value("dependencies").toArray();
       for(int i=0;i<JArray.size();++i) {
           dependencies_List << JArray.at(i).toString();
       }
    }
    //qDebug()<<"dependencies_List: "<<dependencies_List;

    //------------------------------------------------------------
    if(!menu.isEmpty() && !actionList.empty()) {
        emit sig_actions(menu,actionList);
    }
    //------------------------------------------------------------

    //------------------------------------------------------------
    QString widget;
    if(json.keys().contains("widget")) {
        QJsonValue JValue = json.value("widget").toString();
        widget = JValue.toString();

        if(!widget.isEmpty()) {
            sig_widget(loader,widget);  //发送:插件对象、主界面预留接入点
        }
    }
    //------------------------------------------------------------
}

4.3、线程池任务类

#ifndef TRANSMESSAGERUNABLE_H
#define TRANSMESSAGERUNABLE_H

#include <QObject>
#include <QRunnable>
#include <QDebug>

#include "PluginManager.h"
#include "mainwindow.h"

class TransMessageRunable : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit TransMessageRunable(PluginMetaData metaData, QObject *parent = nullptr);
    ~TransMessageRunable();

    PluginMetaData m_metaData;

protected:
    void run();

};

#endif // TRANSMESSAGERUNABLE_H
#include "TransMessageRunable.h"

TransMessageRunable::TransMessageRunable(PluginMetaData metaData, QObject *parent) : QObject(parent)
{
    m_metaData = metaData;
}

TransMessageRunable::~TransMessageRunable()
{
    //qDebug()<<"delete Task";
}

void TransMessageRunable::run()
{
    //和主程序通信
    //------------------------------------------------------------
    if(m_metaData.dest == QString::fromLocal8Bit("mainWin")) {
        if(PluginManager::instance()->m_mainWin) {
            PluginManager::instance()->m_mainWin->recvMsgFromManager(m_metaData);
        }

        return;
    }

    //和插件通信
    //------------------------------------------------------------
    auto loader = PluginManager::instance()->getPlugin(m_metaData.dest); //目标插件
    if(loader) {
        auto interface = qobject_cast<PluginInterface*>(loader->instance());
        if(interface) {
            interface->recMsgFromManager(m_metaData); //转发给对应的插件
        }
    }
}