在前面例子中,我们在 run 函数中定义一系列需要的组件。这就使得对象的初始化工作和业务代码耦合在一起,如下代码:
void run() { // 1. HttpRouter 组件对象 auto router = oatpp::web::server::HttpRouter::createShared(); router->route("GET", "/hello", std::make_shared<Handler>()); // 2. HttpConnectionHandler 组件对象 auto conn_handler = oatpp::web::server::HttpConnectionHandler::createShared(router); // 3. ConnectionProvider 组件对象 auto address = oatpp::network::Address({"localhost", 8000, oatpp::network::Address::IP_4}); auto conn_provider = oatpp::network::tcp::server::ConnectionProvider::createShared(address); oatpp::network::Server server(conn_provider, conn_handler); // 6. 启动服务等待连接 server.run(); }
Oat++ 提供了两个宏 OATPP_CREATE_COMPONENT 和 OATPP_COMPONENT 来将组件对象的初始化工作从 run 函数中剥离到一个单独的文件中,这使得通过替换组件来配置应用程序变得容易。
1. OATPP_CREATE_COMPONENT
接下来,我们使用这两个宏来实现这一部分工作。首先创建一个 AppComponent.hpp,在该文件中使用 OATPP_CREATE_COMPONENT 宏来初始化需要的组件对象,如下代码所示:
#ifndef APPCOMPONENT_HPP #define APPCOMPONENT_HPP #include "oatpp/core/macro/component.hpp" #include "oatpp/web/server/HttpConnectionHandler.hpp" #include "oatpp/network/Server.hpp" #include "oatpp/network/tcp/server/ConnectionProvider.hpp" #include "oatpp/web/server/HttpRouter.hpp" #include "oatpp/web/server/HttpRequestHandler.hpp" #include "oatpp/parser/json/mapping/ObjectMapper.hpp" class AppComponent{ public: // oatpp::base::Environment::Component<std::shared_ptr<oatpp::web::server::HttpRouter>> router = oatpp::base::Environment::Component<std::shared_ptr<oatpp::web::server::HttpRouter>>(lambda) // 将 lambda 函数的返回值作为参数构建 Component, 此时 Compnent 持有了构建的对象 // 将构建好的所有 Component 存储到 unordered_map 容器中,需要的时候使用 OATPP_COMPONENT 从中获取 // OATPP_COMPONENT 多次按照类型获取的对象是同一个 // 注意:默认是根据类型来存储组件对象,如果同类型有多个对象可以尝试使用 NAME 来存储组件对象 OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router)([]{ return oatpp::web::server::HttpRouter::createShared(); }()); OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpConnectionHandler>, conn_handler)([]{ OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); return oatpp::web::server::HttpConnectionHandler::createShared(router); }()); // oatpp::network::ServerConnectionProvider 是 ConnectionProvider 的父类 // 此处也可以写父类类型 OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::tcp::server::ConnectionProvider>, conn_provider)([]{ auto address = oatpp::network::Address({"localhost", 8000, oatpp::network::Address::IP_4}); return oatpp::network::tcp::server::ConnectionProvider::createShared(address); }()); OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::parser::json::mapping::ObjectMapper>, object_mapper)([] { return oatpp::parser::json::mapping::ObjectMapper::createShared(); }()); }; #endif
2. OATPP_COMPONENT
OATPP_CREATE_COMPONENT 执行之后,会预先创建好需要的对象,并存储到容器中,OATPP_COMPONENT 的作用就是从容器中取出组件对象,但是需要注意的是,取对象时是根据类型来获取,多次获取拿到的对象是同一个。
#include "oatpp/network/Server.hpp" #include "oatpp/core/macro/codegen.hpp" #include "AppComponent.hpp" // 必须定义开始 #include OATPP_CODEGEN_BEGIN(DTO) // 该类定义序列化内容,必须继承 DTO 类 class MessageDTO : public oatpp::DTO { // 初始化 DTO_INIT(MessageDTO, DTO); // 定义字段 DTO_FIELD(Int32, status); DTO_FIELD(String, result); DTO_FIELD(String, info); }; // 必须定义结束 #include OATPP_CODEGEN_END(DTO) class Handler : public oatpp::web::server::HttpRequestHandler { public: std::shared_ptr<OutgoingResponse> handle(const std::shared_ptr<IncomingRequest>& request) override { (void)request; // 构建 MessageDTO 对象 auto message = MessageDTO::createShared(); message->status = 200; message->info = "Hello DTO"; message->result = "OK"; // 构建 ObjectMapper 对象,该对象用于序列化 MessageDTO 对象 OATPP_COMPONENT(std::shared_ptr<oatpp::parser::json::mapping::ObjectMapper>, object_mapper); return ResponseFactory::createResponse(Status::CODE_200, message, object_mapper); } }; void run() { // 0. 在 run 函数内作用域范围内注册组件对象 AppComponent components; // 1. 使用 OATPP_COMPONENT 获得 HttpRouter 组件对象 OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); router->route("GET", "/hello", std::make_shared<Handler>()); // 2. 使用 OATPP_COMPONENT 获得 HttpConnectionHandler 组件对象 OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpConnectionHandler>, conn_handler); // 3. 使用 OATPP_COMPONENT 获得 ConnectionProvider 组件对象 OATPP_COMPONENT(std::shared_ptr<oatpp::network::tcp::server::ConnectionProvider>, conn_provider); // 4. 构建服务对象 oatpp::network::Server server(conn_provider, conn_handler); // 5. 服务启动信息 const void *host = conn_provider->getProperty("host").getData(); const void *port = conn_provider->getProperty("port").getData(); OATPP_LOGI("Oat++ Demo", "http://%s:%s/hello", host, port); server.run(); } int main() { oatpp::base::Environment::init(); run(); oatpp::base::Environment::destroy(); return 0; }