EOS开源代码学习笔记(二)插件的初始化
先说明一个上篇笔记中的问题,之前我写eosiod的主体程序中,没有提及到插件的注册。因为我在源代码中没有找到调用插件注册的地方,今天看代码发现,如果插件不注册的话,是无法初始化application类里面的plugins容器的,如果有了解这里的大神,可以帮我解惑。
上篇笔记中,eosiod程序涉及到了三个插件,这三个插件也就是eosiod程序的核心所在。这三个插件分别为chain_plugin、net_plugin和http_plugin。这篇笔记写这三个插件的初始化过程。
一、插件的注册机制去哪里了
Application类的initialize方法是一个模板函数,内部调用initialize_impl函数进行初始化。通过find_plugin函数实现一个vector向量的初始化,如下所示:
template<typename... Plugin>
bool initialize(int argc, char** argv) {
return initialize_impl(argc, argv, {find_plugin<Plugin>()...});
}
template<typename Plugin>
Plugin* find_plugin()const {
string name = boost::core::demangle(typeid(Plugin).name());
return dynamic_cast<Plugin*>(find_plugin(name));
}
函数返回abstract_plugin对象指针,find_plugin函数进行重载
abstract_plugin* application::find_plugin(const string& name)const
{
auto itr = plugins.find(name); //plugins容器没有初始化
if(itr == plugins.end()) {
return nullptr;
}
return itr->second.get();
}
find_plugin函数功能是通过遍历plugins容器,返回插件对象的指针。需要注意的是,在application类里面对于函数find_plugin进行了重载,而plugins容器是需要插件进行注册来进行初始化的,但是没有发现插件注册的代码,也可能是我对于代码的理解不够。
这三个插件类继承自plugin基类,使用虚函数来进行多态实现,然后将三个功能模块作为插件添加到eosiod程序中,正是由于这种插件类型设计方式,eosiod的出块功能、p2p网络功能、http功能可能会部署在不同的机器上,给见证人节点以集群的方式部署自己的架构,提供了可能。
template<typename Plugin>
auto& register_plugin() {
auto existing = find_plugin<Plugin>();
if(existing)
return *existing;
auto plug = new Plugin();
plugins[plug->name()].reset(plug);
plug->register_dependencies();
return *plug;
}
通过register_plugin()方法注册不同类型的插件,目的是初始化application类中的成员变量的plugins容器,只有注册过的插件,才能在find_plugin()方法里面初始化插件vector向量,才能进行后续的初始化工作。
二、插件的初始化过程
application 类中的initialize_impl方法的实现
bool application::initialize_impl(int argc, char** argv, vector<abstract_plugin*> autostart_plugins) {
set_program_options();
bpo::variables_map options;
bpo::store(bpo::parse_command_line(argc, argv, my->_app_options), options);
if( options.count( "help" ) ) {
cout << my->_app_options << std::endl;
return false;
}
// .....省略部分代码
// 第二部分功能
for (auto plugin : autostart_plugins)
if (plugin != nullptr && plugin->get_state() == abstract_plugin::registered)
plugin->initialize(options);
bpo::notify(options);
return true;
}
通过代码,我们知道,eosiod采用了boost库中的program_options库来解析命令行参数和配置。eosiod程序的初始化可以分成两部分功能,一部分是解析命令行参数和配置。二部分是根据配置信息对于每一个加载的插件进行初始化。
简要说明:使用program_options库来解析命令行参数,主要用到选项描述器(options_description)、选项存储器(variables_map,继承自map类)。使用options.count来检查是否输入了该参数。
第二部分是遍历注册的插件vector向量,获取每个插件对象指针,调用其插件子类的initialize函数进行初始化,参数为选项存储器options,即一个map类型的键值对链表,http_plugin插件类的定义。
class http_plugin : public appbase::plugin<http_plugin>
{
public:
http_plugin();
virtual ~http_plugin();
APPBASE_PLUGIN_REQUIRES()
virtual void set_program_options(options_description&, options_description& cfg) override;
void plugin_initialize(const variables_map& options);
void plugin_startup();
void plugin_shutdown();
void add_handler(const string& url, const url_handler&);
void add_api(const api_description& api) {
for (const auto& call : api)
add_handler(call.first, call.second);
}
private:
std::unique_ptr<class http_plugin_impl> my;
};
以前的文章:
EOS开源代码学习笔记(一) eosiod程序
qq群:694228458 ,用于eos开发学习交流
Leave EOS开源代码学习笔记(二)插件的初始化 to:
Read more #cn posts
Best Posts From mooninwater
We have not curated any of mooninwater's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.