一般地,基于POCO框架的程序结构都是按模块化架构的。
模块化处理过程主要涉及两个头文件:
poco/1.4/Foundation/include/Poco/ClassLibrary.h
poco/1.4/Foundation/include/Poco/ClassLoader.h
ClassLibrary.h |
此头文件的主要目的是单独导出三个函数供外部其他模块调用,实际就是ClassLoder.h中类的方法调用。
#define POCO_LIBRARY_API __declspec(dllexport)
extern "C"
{
bool POCO_LIBRARY_API pocoBuildManifest(Poco::ManifestBase* pManifest);
void POCO_LIBRARY_API pocoInitializeLibrary();
void POCO_LIBRARY_API pocoUninitializeLibrary();
}
这个头文件中主要是申明了四个用于导出库中类的宏。其中库中的类需要满足,每一个类都继承自同一个基类。
POCO_BEGIN_MANIFEST(IModule)
POCO_EXPORT_CLASS(WebModule)
POCO_EXPORT_SINGLETON(OtherModule) //以单例模式导出而已,不懂的可以去查询一下设计模式的相关概念
POCO_END_MANIFEST
其中IMdoule是抽象基类,WebModule、OtherModule是继承它的子类。最终模块就可以基于以上几个宏导出库中的WebModule、OtherModule类。
以上宏的主要内容如下:
#define POCO_BEGIN_MANIFEST(base) \
POCO_BEGIN_MANIFEST_IMPL(pocoBuildManifest, base)
#define POCO_BEGIN_MANIFEST_IMPL(fnName, base) \
bool fnName(Poco::ManifestBase* pManifest_) \
{ \
typedef base _Base; \
typedef Poco::Manifest<_Base> _Manifest; \
std::string requiredType(typeid(_Manifest).name()); \
std::string actualType(pManifest_->className()); \
if (requiredType == actualType) \
{ \
Poco::Manifest<_Base>* pManifest = static_cast<_Manifest*>(pManifest_);
#define POCO_EXPORT_CLASS(cls) \
pManifest->insert(new Poco::MetaObject<cls, _Base>(#cls));
#define POCO_EXPORT_SINGLETON(cls) \
pManifest->insert(new Poco::MetaSingleton<cls, _Base>(#cls));
#define POCO_END_MANIFEST \
return true; \
} \
else return false; \
}
以上四个宏的展开后如下:
bool pocoBuildManifest(Poco::ManifestBase* pManifest_)
{
//typedef IModule _Base;
//typedef Poco::Manifest<IModule> _Manifest;
std::string requiredType(typeid(Poco::Manifest<IModule>).name());
std::string actualType(pManifest_->className());
if (requiredType == actualType)
{
Poco::Manifest<IModule>* pManifest = static_cast<Poco::Manifest<IModule>*>(pManifest_);
pManifest->insert(new Poco::MetaObject<WebModule, IModule>("WebModule"));
pManifest->insert(new Poco::MetaSingleton<OtherModule, IModule>("OtherModule"));
return true;
}
else return false;
}
在讲解这个函数的功能之前,先需要说明一下参数关系结构:
Poco::Manifest<IModule>*>
是继承自Poco::ManifestBase
宏展开之后仅是组成了一个pocoBuildManifest
函数,函数的主要目的是:
1. 首先把传入的参数Poco::ManifestBase* pManifest_
转换为Poco::Manifest<IModule>* pManifest
2. 调用pManifest->insert()
函数,把由WebModule、IModule作为参数构成的Poco::MetaObject
元对象(后续库中关于类对象的创建都是由此元对象完成)插入到Poco::Manifest<IModule>
“菜单”中
前面也提到了,上面导出的三个函数最终都是在ClassLoader.h文件中调用。
在使用库之前,需要加载对应的库,但在加载之前,需要创建两个基于库中所包含导出类的基类的对象。
typedef ClassLoader<IModule> PluginLoader;
typedef Manifest<IModule> PluginManifest;
实际库的加载是通过调用
PluginLoader loader.loadLibrary(path); //path为库的全路径,包括后缀
loadLibrary(path) —> loadLibrary(path, “”)
struct LibraryInfo
{
SharedLibrary* pLibrary;
const Manif* pManifest;
int refCount;
};
void loadLibrary(const std::string& path, const std::string& manifest)
{
FastMutex::ScopedLock lock(_mutex);
typename LibraryMap::iterator it = _map.find(path); //std::map<std::string, LibraryInfo> _map
if (it == _map.end())
{
LibraryInfo li;
li.pLibrary = new SharedLibrary(path); //根据库的路径加载此库,生成一个SharedLibrary对象
li.pManifest = new Manif(); //生成一个库的菜单,用于记录库中所包含的导出信息
li.refCount = 1; //库被引用的次数
try
{
std::string pocoBuildManifestSymbol("pocoBuildManifest");
pocoBuildManifestSymbol.append(manifest);
if (li.pLibrary->hasSymbol("pocoInitializeLibrary")) //查询库中是否存在导出符号pocoInitializeLibrary
{
InitializeLibraryFunc initializeLibrary = (InitializeLibraryFunc) li.pLibrary->getSymbol("pocoInitializeLibrary"); //如果存在此导出符号,就获取它的实例,是一个函数指针
initializeLibrary(); //调用此函数
}
if (li.pLibrary->hasSymbol(pocoBuildManifestSymbol))
{ //查询库中是否存在pocoBuildManifest符号,此符号就是由先前的ClassLibrary.h中的宏设计导出的,
//用于把导出的类所构成的元对象插入到菜单中,最为关键的函数,成功后需要把此LibraryInfo结构存入loader的_map中
BuildManifestFunc buildManifest = (BuildManifestFunc) li.pLibrary->getSymbol(pocoBuildManifestSymbol);
if (buildManifest(const_cast<Manif*>(li.pManifest)))
_map[path] = li;
else
throw LibraryLoadException(std::string("Manifest class mismatch in ") + path, manifest);
}
else throw LibraryLoadException(std::string("No manifest in ") + path, manifest);
}
catch (...)
{
delete li.pLibrary;
delete li.pManifest;
throw;
}
}
else
{
++it->second.refCount;
}
}
至此,根据路径path已经成功加载了相应的库了,接下来就是库中导出类对象的引用了。
此引用过程有两种方法:
1. 直接生成菜单,然后根据菜单的迭代器遍历菜单,对库菜单的每一项进行实际对象创建、初始化、加入向量
//typedef Manifest<IModule> PluginManifest;
Manifest<Base> man = loader.manifestFor(path);
PluginManifest::Iterator itMan = begin(man); //菜单的迭代器首项
PluginManifest::Iterator endMan = end(man); //菜单的迭代器尾部
for(; itMan != endMan; ++itMan)
{
string name = itMan->name(); //菜单迭代器指向的name,实际就是class的名字,如“WebModule”
try
{
//实际调用元对象的create函数,根据类名,由元对象MetaObject创建导出类的实际对象
auto module = loader.create(name);
module->Initialize(); //调用导出类的Initialize接口
loadedModules.push_back(module); //把此对象压入vector<IModule*>向量
}
...
}
2. 直接获取loader的迭代器,然后遍历loader中的每一项,通过迭代器的first获得库的路径,迭代器的second获得此loader其中一个库的菜单项,然后遍历此菜单项,过程也就同1了
loader.loadLibrary(path);
PluginLoader::Iterator it(loader.begin());
PluginLoader::Iterator end(loader.end());
for (; it != end; ++it)
{
std::cout << "lib path: " << it->first << std::endl;
PluginManifest::Iterator itMan(it->second->begin());
PluginManifest::Iterator endMan(it->second->end());
for (; itMan != endMan; ++itMan)
{
auto module = loader.create(name);
module->Initialize(); //调用导出类的Initialize接口
loadedModules.push_back(module); //把此对象压入vector<IModule*>向量
}
}
loader.classFor("WebModule").autoDelete(WebModule); //释放创建的WebModule对象
delete OtherModule; //释放创建的对象
loader.unloadLibrary(path); //卸载加载的库
至此、POCO开源框架的库中类型加载、使用、卸载过程全部介绍完成。