POCO开源框架-模块加载卸载过程分析

一般地,基于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()函数,把由WebModuleIModule作为参数构成的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开源框架的库中类型加载、使用、卸载过程全部介绍完成。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会为您解析 Poco C++库网络模块的 HttpServer 示例。 HttpServer 是一个用于创建 HTTP 服务器的类,可以用于处理 HTTP 请求和响应。下面是一个简单的 HttpServer 示例,它监听来自客户端的请求并返回一个简单的响应: ```cpp #include "Poco/Net/HTTPServer.h" #include "Poco/Net/ServerSocket.h" #include "Poco/Util/ServerApplication.h" #include "Poco/Net/HTTPRequestHandlerFactory.h" #include "Poco/Net/HTTPRequestHandler.h" #include "Poco/Net/HTTPServerRequest.h" #include "Poco/Net/HTTPServerResponse.h" #include <iostream> using namespace Poco::Net; using namespace Poco::Util; using namespace std; class MyRequestHandler: public HTTPRequestHandler { public: void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) { response.setChunkedTransferEncoding(true); response.setContentType("text/html"); ostream& ostr = response.send(); ostr << "<html><head><title>My 1st HTTP Server</title></head>"; ostr << "<body><h1>Hello, world!</h1></body></html>"; } }; class MyRequestHandlerFactory: public HTTPRequestHandlerFactory { public: HTTPRequestHandler* createRequestHandler(const HTTPServerRequest&) { return new MyRequestHandler; } }; class MyServerApp: public ServerApplication { protected: int main(const vector<string>&) { HTTPServer server(new MyRequestHandlerFactory, ServerSocket(8080), new HTTPServerParams); server.start(); cout << "Server started" << endl; waitForTerminationRequest(); server.stop(); cout << "Server stopped" << endl; return Application::EXIT_OK; } }; int main(int argc, char** argv) { MyServerApp app; return app.run(argc, argv); } ``` 在这个示例中,我们定义了一个 MyRequestHandler 类来处理 HTTP 请求。这个类只有一个方法 handleRequest,它接收 HTTPServerRequest 对象和 HTTPServerResponse 对象作为参数。 handleRequest 方法设置 HTTP 响应的头信息,然后通过 HTTPServerResponse 对象发送响应的正文。代码中发送的响应正文是一个简单的 HTML 页面,其中包含一个标题和一个“Hello, world!”的消息。 MyRequestHandlerFactory 类是一个工厂类,它实现了 HTTPRequestHandlerFactory 接口。当服务器接收到一个新的请求时,它调用 MyRequestHandlerFactory 的 createRequestHandler 方法来创建一个新的 MyRequestHandler 对象来处理该请求。 MyServerApp 类继承了 ServerApplication 类,它用于启动和停止 HTTP 服务器。在 main 方法中,我们创建了一个 HTTPServer 对象,并将 MyRequestHandlerFactory、ServerSocket 和 HTTPServerParams 对象传递给它。然后,我们调用 HTTPServer 对象的 start 方法来启动服务器,并调用 waitForTerminationRequest 方法来等待服务器终止请求。最后,我们调用 HTTPServer 对象的 stop 方法来停止服务器。 这就是 Poco C++库网络模块中的 HttpServer 示例的解析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值