日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【问链-EOS公开课】第十三课 EOS插件机制深入解析

發布時間:2025/3/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【问链-EOS公开课】第十三课 EOS插件机制深入解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

插件體系
EOS插件由三層類來實現。

最頂層是抽象類abstract_plugin,定義了插件的基本接口。
中間層是插件模板類plugin,主要用來解決插件之間依賴調用。
最底層是具體插件類,專注單個插件的業務功能實現。

nodeos進程啟動后第一步是注冊插件,在eos/programs/nodeos/main.cpp中看到

int main(int argc, char** argv) {...// 注冊插件app().register_plugin<net_api_plugin>();...app().register_plugin<faucet_testnet_plugin>();// app初始化if(!app().initialize<chain_plugin, http_plugin, net_plugin>(argc, argv))return -1;... }

應用程序通過app()返回一個application類的實例對象,這里采用單例模式,保證整個系統訪問的是同一個全局對象,具體實現:

libraries/appbase/application.cpp

application& application::instance() {static application _app; return _app; } application& app() { return application::instance(); }

在加載使用插件前,需要通過register_plugin()函數將插件注冊到application的plugins插件集合中,plugins是一個map容器,通過鍵值對管理插件名稱和插件對象指針,方便通過插件名稱查找插件對象。

static appbase::abstract_plugin& _producer_plugin = app().register_plugin(); class application {…template auto& register_plugin() {auto existing = find_plugin();// 根據類名字查找已經注冊的插件集 if(existing)// 已經注冊過的就不再重復注冊return *existing;// 返回插件引用 auto plug = new Plugin();//還沒注冊的就new一個插件對象 plugins[plug->name()].reset(plug); // 根據類名注冊到插件集中 plug->register_dependencies(); // 注冊插件的下一級依賴 return *plug;//返回注冊插件引用}…map plugins;… }

查找插件
注冊插件集合使用了application的map類成員plugins,注冊key是插件類名,value是指向插件抽象對象的指針,并且使用了std::unique_ptr防止插件對象被非法引用。插件抽象類定義了插件的必要接口,包括當前狀態、名字、初始化、啟停接口,所有的具體插件都要實現這些接口。

map<string, std::unique_ptr<abstract_plugin>> plugins; ///< 所有注冊的插件對象// 插件抽象類定義了插件的必要接口class abstract_plugin {public:enum state {registered, ///< 插件已經構建但還沒做任何事情 the plugin is constructed but doesn't do anythinginitialized, ///< 插件已經初始化所有狀態,但仍處于待啟動狀態 the plugin has initialized any state required but is idlestarted, ///< 插件已經啟動,在運行中 the plugin is actively runningstopped ///< 插件已經停止 the plugin is no longer running};virtual ~abstract_plugin(){}virtual state get_state()const = 0; // 插件當前狀態virtual const std::string& name()const = 0; // 名字virtual void set_program_options( options_description& cli, options_description& cfg ) = 0; // 設定命令行/配置文件中允許的可配置選項virtual void initialize(const variables_map& options) = 0; // 初始化virtual void startup() = 0; // 啟動插件virtual void shutdown() = 0; // 停止插件};// application的find_plugin模板成本函數 class application { ...template<typename Plugin>Plugin* find_plugin()const {// 利用boost工具獲取插件類名,再到注冊類集合中查找string name = boost::core::demangle(typeid(Plugin).name());return dynamic_cast<Plugin*>(find_plugin(name));} ... }

插件依賴注冊
插件之間可能存在依賴關系,譬如net_api_plugin依賴net_plugin和http_plugin,即application想要使用net_api_plugin必須要保證另外兩個插件也被注冊。
具體插件通過實例化插件模板類來定義,需要指定具體插件類作為模板參數。在模板類的register_dependencies函數里調用了子類的plugin_requires函數,傳入了一個空的函數閉包。

// 插件模板類,需要指定具體插件類作為模板參數template<typename Impl>class plugin : public abstract_plugin {...virtual void register_dependencies() {static_cast<Impl*>(this)->plugin_requires([&](auto& plug){});}...}

我們看到具體插件類中,是通過宏APPBASE_PLUGIN_REQUIRES來定義plugin_requires,這個宏的參數指定了當前插件所依賴的其他插件。

#define APPBASE_PLUGIN_REQUIRES_VISIT( r, visitor, elem ) \visitor( appbase::app().register_plugin<elem>() );#define APPBASE_PLUGIN_REQUIRES( PLUGINS ) \template<typename Lambda> \void plugin_requires( Lambda&& l ) { \BOOST_PP_SEQ_FOR_EACH( APPBASE_PLUGIN_REQUIRES_VISIT, l, PLUGINS ) \}class net_api_plugin : public plugin<net_api_plugin> { public:// net_api_plugin依賴了net_plugin和http_plugin兩個插件APPBASE_PLUGIN_REQUIRES((net_plugin) (http_plugin)) ... }

對宏展開如下,包含了對net_plugin和http_plugin的注冊。

class net_api_plugin : public plugin<net_api_plugin> { public:void plugin_requires( Lambda&& l ) {lambda(appbase::app().register_plugin<net_plugin>());lambda(appbase::app().register_plugin<http_plugin>());} ... }

lambda表達式的傳入參數是注冊后的插件對象引用,不過,register_dependencies里的lambda是[&](auto& plug){},實際執行體為空,所以沒有對依賴的插件做進一步處理。

插件初始化、啟停
插件模板類除了定義register_dependencies注冊依賴,還定義了插件初始化、啟動、停止三個方法。

initialize和startup方法同register_dependencies一樣,調用具體子類的plugin_requires,但是傳入了包含實際處理的lambda閉包,來調用所依賴的插件執行初始化/啟動。下級插件完成處理后,執行本插件的具體插件類的處理方法plugin_initialize和plugin_startup。
啟動程序

加載插件后,遍歷調用initialized_plugins集合中各個插件實例的startup()函數,啟動插件任務,例如producer_plugin插件的啟動函數為producer_plugin::plugin_startup(),主要功能是循環生產區塊:

void application::startup() {for (auto plugin : initialized_plugins)plugin->startup(); }class plugin : public abstract_plugin {virtual void startup() override {…static_cast(this)->plugin_startup();…} }class producer_plugin : public appbase::plugin {…virtual void plugin_startup();… }void producer_plugin::plugin_startup() { …my->schedule_production_loop(); // 循環生產區塊 … }

shutdown方法由app統一調度所有已注冊過(直接或間接注冊)的插件shutdown,所以無需進一步調用依賴的插件執行。

template<typename Impl>class plugin : public abstract_plugin {...virtual void initialize(const variables_map& options) override {if(_state == registered) {_state = initialized;// 對下級依賴插件調用初始化static_cast<Impl*>(this)->plugin_requires([&](auto& plug){ plug.initialize(options); });// 當前插件初始化static_cast<Impl*>(this)->plugin_initialize(options);//ilog( "initializing plugin ${name}", ("name",name()) );app().plugin_initialized(*this); // 在application中記錄}assert(_state == initialized); /// if initial state was not registered, final state cannot be initiaized}virtual void startup() override {if(_state == initialized) {_state = started;static_cast<Impl*>(this)->plugin_requires([&](auto& plug){ plug.startup(); });static_cast<Impl*>(this)->plugin_startup();app().plugin_started(*this);}assert(_state == started); // if initial state was not initialized, final state cannot be started}virtual void shutdown() override {if(_state == started) {_state = stopped;//ilog( "shutting down plugin ${name}", ("name",name()) );static_cast<Impl*>(this)->plugin_shutdown();}}... }

各個插件初始化并啟動完成后,最后設置應用程序的信號處理函數,用來響應用戶終止動作,例如,ctrl + c:

void application::exec() {sigint_set->async_waitio_serv->run(); // 異步等待信號事件發生。shutdown() // 應用退出后關閉插件。 }

總結
EOS采用石墨烯引擎為基礎構建區塊鏈,并且實現了一套靈活的模塊化插件機制,在抽象插件類和具體功能類之間引入一層模板類,來將插件間依賴調用從具體類中解耦出來,有利于插件功能內聚以及新插件擴展。

總結

以上是生活随笔為你收集整理的【问链-EOS公开课】第十三课 EOS插件机制深入解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。