在eos源码目录中programs/nodeos/main.cpp文件里,为节点启动的主函数
main函数内部做了两件事
1 初始化 application
1 | if(!app().initialize<chain_plugin, http_plugin, net_plugin, producer_plugin>(argc, argv)) |
2 application启动和插件启动
1 | app().startup(); |
application类
先说application的基本实现和常用接口,application 定义了注册插件的函数,获取插件,查找插件等功能,根据模板动态绑定的
同样定义了一些私有函数和变量
application 构造函数为私有的,方便实现单例模式,plugins为存储各类注册插件的map,key为插件名,value为独占的基类指针,不可copy。
io_serv为boost库提供的io_service的shared_ptr,网络通信和事件注册派发会用到。initialized_plugins为已经初始化的插件vector,
running_plugins为已经runing的插件vector。
erased_method_ptr和erased_channel_ptr分别在method.hpp和channel.hpp中实现了定义,以后用到再分析。
application类protected部分包含三个函数
initialize_impl 根据配置初始化插件。
plugin_initialized 将插件放入初始化vector
plugin_started 将插件放入runing vector
下面是application实现的单例模式,定义全局函数app(),内部调用application类静态函数instance()
application的start函数内部调用了各个插件的startup,出现异常shutdown
exec()内部注册了SIGINT,SIGTERM,SIGPIPE信号,当进程收到这几个信号会导致ioservice->stop(),否则io_ser->run()一直监听等待就绪事件
plugin类
abstract_plugin为所有插件继承的纯虚类,不同插件会实现各自特有的功能
plugin.hpp中定义了
BOOST_PP_SEQ_FOR_EACH为boost定义的宏,按照参数PLUGINS依次展开,将lambda函数l和每个PLUGIN传入
APPBASE_PLUGIN_REQUIRES_VISIT,比如net_api_plugin展开
展开后
1 | void plugin_requires( Lambda&& l ) { |
就是采用注册的lambda表达式依次调用,并且将各个插件注册到application中。
plugin 继承了abstract_plugin类
Impl是模板类型,不同的插件会传入不同的模板类型,initialize,startup,shutdown为虚函数,重写了基类abstract_plugin的功能。内部通过
static_cast<Impl*>(this)转化为对应的不同模板类型的plugin,进而实现特定功能的绑定,初始化,启动,停止等。举例:
net_plugin 继承了plugin,并且模板类型为net_plugin,这样当plugin
1 | static_cast<net_plugin*>(this)->plugin_requires([&](auto& plug){ plug.initialize(options); }); |
APPBASE_PLUGIN_REQUIRES((chain_plugin))展开
1 | void plugin_requires( Lambda&& l ) { |
所以static_cast<net_plugin*>(this)->plugin_requires([&](auto& plug){ plug.initialize(options); });
实际继续展开内部调用appbase::app().register_plugin
startup,shutdown也是一样的道理。