在前面例子中,我们在 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 函数中剥离到一个单独的文件中,这使得通过替换组件来配置应用程序变得容易。
- OATPP_CREATE_COMPONENT {#title-0} ====================================
接下来,我们使用这两个宏来实现这一部分工作。首先创建一个 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
- OATPP_COMPONENT {#title-1} =============================
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;
}