目录
1 概述
应用模块化难免会使用插件的方式,这里使用纯C++方式实现插件的封装,及插件加载器泛型动态加载。按照这种套路,可以封装及批量加载不同类型的自定义插件。
2 插件封装
需要注意的是,这里的插件是以动态库的形式导出。
2.1 定义插件类型为module_plugin的插件基类
modulebase.h
// modulebase.h
// ...
//
// Created by xxx on 2021/3/28.
// Copyright 2021 xxx, Inc. All rights reserved.
//
#ifndef MIDDLEWARE_MODULE_MODULEBASE_H_
#define MIDDLEWARE_MODULE_MODULEBASE_H_
#include <string>
namespace module {
static const char g_module_plugin_type[] = "module_plugin";
class ModuleBase {
public:
explicit ModuleBase(const std::string name)
: name_(name) {
}
virtual ~ModuleBase() {}
std::string name() const { return name_; }
void set_name(std::string name) { name_ = name; }
virtual void Test() = 0;
private:
std::string name_;
};
} // namespace module
#endif // MIDDLEWARE_MODULE_MODULEBASE_H_
2.2 radiomodule插件
radiomodule.h
// radiomodule.h
// ...
//
// Created by xxx on 2021/3/28.
// Copyright 2021 xxx, Inc. All rights reserved.
//
#ifndef MIDDLEWARE_MODULE_RADIOMODULE_RADIOMODULE_H_
#define MIDDLEWARE_MODULE_RADIOMODULE_RADIOMODULE_H_
#include <memory>
#include "middleware/module/modulebase.h"
namespace module {
class RadioModule : public ModuleBase {
public:
RadioModule();
~RadioModule();
virtual void Test();
// Factory method
static RadioModule *Create() {
return new RadioModule();
}
};
extern "C" const char *Type() {
return g_module_plugin_type;
}
extern "C" void* Create() {
return module::RadioModule::Create();
}
} // namespace module
#endif // MIDDLEWARE_MODULE_RADIOMODULE_RADIOMODULE_H_
radiomodule.cpp
// radiomodule.cpp
// ...
//
// Created by xxx on 2021/3/28.
// Copyright 2021 xxx, Inc. All rights reserved.
//
#include "middleware/module/radiomodule/radiomodule.h"
#include "apis/logger/logger.h"
namespace module {
RadioModule::RadioModule()
: ModuleBase("radio_module") {
}
RadioModule::~RadioModule() {
}
void RadioModule::Test() {
LOGGING->Log(L_INFO , "%s" , __FUNCTION__);
}
} // namespace module
2.3 bluetoothmodule插件
bluetoothmodule.h
// bluetoothmodule.h
// ...
//
// Created by xxx on 2021/3/28.
// Copyright 2021 xxx, Inc. All rights reserved.
//
#ifndef MIDDLEWARE_MODULE_BLUETOOTHMODULE_BLUETOOTHMODULE_H_
#define MIDDLEWARE_MODULE_BLUETOOTHMODULE_BLUETOOTHMODULE_H_
#include <memory>
#include "middleware/module/modulebase.h"
namespace module {
class BlueToothModule : public ModuleBase {
public:
BlueToothModule();
~BlueToothModule();
virtual void Test();
// Factory method
static BlueToothModule *Create() {
return new BlueToothModule();
}
};
extern "C" const char *Type() {
return g_module_plugin_type;
}
extern "C" void* Create() {
return module::BlueToothModule::Create();
}
} // namespace module
#endif // MIDDLEWARE_MODULE_BLUETOOTHMODULE_BLUETOOTHMODULE_H_
bluetoothmodule.cpp
// bluetoothmodule.cpp
// ...
//
// Created by xxx on 2021/3/28.
// Copyright 2021 xxx, Inc. All rights reserved.
//
#include "middleware/module/bluetoothmodule/bluetoothmodule.h"
#include "apis/logger/logger.h"
namespace module {
BlueToothModule::BlueToothModule()
: ModuleBase("bluetooth_module") {
}
BlueToothModule::~BlueToothModule() {
}
void BlueToothModule::Test() {
LOGGING->Log(L_INFO , "%s" , __FUNCTION__);
}
} // namespace module
3 插件加载
3.1 插件加载器
pluginloader.h
// pluginloader.h
// ...
//
// Created by xxx on 2021/3/28.
// Copyright 2021 xxx, Inc. All rights reserved.
//
#ifndef APIS_PLUGINLOADER_H_
#define APIS_PLUGINLOADER_H_
#include <dlfcn.h>
#include <dirent.h>
#include <vector>
#include <string>
#include <memory>
// #include "apis/logger/logger.h"
namespace api {
typedef void* PluginCreate();
typedef const char *PluginType();
template <class T>
void LoadPlugins(
std::string path,
std::string type,
std::vector<std::shared_ptr<T>> *plugin_vector) {
if (nullptr == plugin_vector)
return;
DIR *plugins_dir = opendir(path.c_str());
if (plugins_dir == nullptr) {
// LOGGING->Log(L_WARNING, "open path %s failed." , path.c_str());
return;
}
// LOGGING->Log(L_DEBUG,
// "enter path (%s) ,load plugins (%s).",
// path.c_str(),
// type.c_str());
struct dirent *file_info = nullptr;
while ((file_info = readdir(plugins_dir)) != nullptr) {
std::string file_name(file_info->d_name);
int pos = file_name.find_last_of('.');
std::string suffix = pos >= 0? file_name.substr(pos) : "";
if (suffix == ".so") {
std::string file_path = path + "/" + file_name;
try {
void* handle = dlopen(file_path.c_str() , RTLD_LAZY);
if (nullptr == handle) {
// LOGGING->Log(L_DEBUG , "error: %s" , dlerror());
continue;
}
PluginType* type_func = reinterpret_cast<PluginType*>(
dlsym(handle , "Type"));
if (nullptr == type_func) {
dlclose(handle);
continue;
}
if (type != type_func()) {
dlclose(handle);
continue;
}
PluginCreate* create_func = reinterpret_cast<PluginCreate*>(
dlsym(handle , "Create"));
if (nullptr == create_func) {
dlclose(handle);
continue;
}
// LOGGING->Log(L_DEBUG,
// "load plugin (%s) sucssesed.",
// file_path.c_str());
std::shared_ptr<T> plugin;
plugin.reset(static_cast<T*>(create_func()));
plugin_vector->push_back(plugin);
} catch ( const std::exception & ex ) {
// LOGGING->Log(L_ERROR , "error: %s" , ex.what());
continue;
}
}
}
}
} // namespace api
#endif // APIS_PLUGINLOADER_H_
3.2 加载调用示例
// other
#include "middleware/module/modulebase.h"
#include "apis/pluginloader.h"
// other
// other
std::vector<std::shared_ptr<ModuleBase>> module_vector;
std::string plugin_path = "./plugins/module";
api::LoadPlugins(plugin_path,
"module_plugin",
&module_vector);
// other