【问题标题】:node.js: injecting dependencies in app.jsnode.js:在 app.js 中注入依赖项
【发布时间】:2017-11-26 08:02:17
【问题描述】:

我正在使用 node.js 和 typescript 开发一个应用程序。我按照本文中概述的方法 http://brianflove.com/2016/11/08/typescript-2-express-node/ 对 server.ts 文件进行了模式化,以下是 server.ts 文件的示例代码:

import * as bodyParser from "body-parser";
import * as cookieParser from "cookie-parser";
import * as express from "express";
import * as logger from "morgan";
import * as path from "path";
import errorHandler = require("errorhandler");
import methodOverride = require("method-override");

/**
 * The server.
 *
 * @class Server
 */
export class Server {

    public app: express.Application;

    /**
     * Bootstrap the application.
     *
     * @class Server
     * @method bootstrap
     * @static
     * @return {ng.auto.IInjectorService} Returns the newly created injector for this app.
     */
    public static bootstrap(): Server {
        return new Server();
    }

    /**
     * Constructor.
     *
     * @class Server
     * @constructor
     */
    constructor() {
        //create expressjs application
        this.app = express();

        //configure application
        this.config();

        //add routes
        this.routes();

        //add api
        this.api();
    }

    /**
     * Create REST API routes
     *
     * @class Server
     * @method api
     */
    public api() {
        //empty for now
    }

    /**
     * Configure application
     *
     * @class Server
     * @method config
     */
    public config() {
        //empty for now
    }

    /**
     * Create router
     *
     * @class Server
     * @method api
     */
    public routes() {
        //empty for now
    }
}

这里是路由函数的示例代码:

/**
  * Create router.
  *
  * @class Server
  * @method config
  * @return void
  */
private routes() {
  let router: express.Router;
  router = express.Router();
  //let mymodel = this.connection.model<IMyModel>("MyModel", MySchema);
  //let myservice: MyService = new MyService(this.myRepository(mymodel));


  //IndexRoute
  IndexRoute.create(router, myservice);

  //use router middleware
  this.app.use(router);
}

对于我的特定场景,我将服务注入到路由中以执行可能需要执行的适当操作。这是我关心的问题,如果我以这种方式将服务注入控制器。这是否意味着每个发出请求的人都会收到不同的服务和存储库或相同的实例?理想情况下,我想如果每个用户收到不同的实例会更好。这将如何影响在存储库层中进行的数据库调用?我是 node.js 的新手,但我仍在尝试理解 app.js、server.js 和请求之间的关系,因为 node.js 是单线程的。

【问题讨论】:

    标签: node.js typescript repository-pattern service-layer


    【解决方案1】:

    这是否意味着每个发出请求的人都会收到不同的服务和存储库或相同的实例

    在您的示例中,所有请求都将使用MyService 的相同实例。

    只要确保依赖图中的所有类都是无状态的,这不是什么大问题。

    我想如果每个用户收到不同的实例会更好。

    我同意你的看法。我更喜欢每个请求一个实例的想法。

    这将如何影响在存储库层中进行的数据库调用?

    正如我所说,只要您不在请求之间共享状态,这应该不是问题。一些数据库推荐一个唯一的永久连接(例如节点)。在这种情况下,与单例共享相同的存储库是个好主意。

    app.js、server.js之间的关系

    server.js 是我们在其中创建并开始运行一个或多个应用程序的文件。每个应用程序通常在不同的 VHOST 或 PORT 上运行。

    并且作为 node.js 发出的请求是单线程的

    Node.js 使用非阻塞模型。当您向数据库发送查询时,Node.js 将继续处理其他请求。这意味着主线程不会被查询阻塞。当查询返回时,主线程将选择事件并继续执行请求。

    另一种方法

    我创建了一个库,可以让您更好地控制依赖项的注入和范围。例如,您不需要执行以下操作:

    let mymodel = this.connection.model<IMyModel>("MyModel", MySchema);
    let myservice: MyService = new MyService(this.myRepository(mymodel));
    

    您可以声明一个要注入的类及其依赖项:

    @injectable()
    class MyService() {
    
        @inject("IMyModel") private mymodel: IMyModel;
    
        // ...
    }
    

    另外,不要像这样声明路由:

    IndexRoute.create(router, myservice);
    

    你可以使用像@Get这样的装饰器

    @injectable()
    class MyService() {
    
        @inject("IMyModel") private mymodel: IMyModel;
    
        @Get("/someURL")
        public async get() {
            return await this.mymodel.readAll();
        }
    
    }
    

    最后,要控制生命周期,您只需要使用不同类型的绑定即可。

    所有请求共享一个实例:

    container.bind<MyService>("MyService").to(MyService).inSingletonScope();
    

    每个请求都有一个新实例:

    container.bind<MyService>("MyService").to(MyService).inTransientScope();
    

    以下是具有 HTTP GET 端点的控制器的真实示例:

    import { Controller, Get } from "inversify-express-utils";
    import { injectable } from "inversify";
    import { Repository } from "@lib/universal/interfaces/infra";
    import { Aircraft } from "@lib/universal/interfaces/aviation";
    import { authorize } from "@lib/server/auth/auth_middleware";
    import { referenceDataPaths } from "@stellwagen/universal/config/app_paths";
    import { FEATURE } from "@lib/server/constants/privileges";
    import { aircraftRepository } from "../ioc_module/decorators";
    
    @injectable()
    @Controller(
        referenceDataPaths.server.aircraft.name,
        authorize({ feature: FEATURE.APP_ACCESS_REFERENCE_DATA })
    )
    class AircraftController {
    
        @aircraftRepository private readonly _aircraftRepository: Repository<Aircraft>;
    
        @Get(referenceDataPaths.server.aircraft.endpoints.get)
        public async get() {
            return await this._aircraftRepository.readAll();
        }
    
    }
    
    export { AircraftController };
    

    库是inversify-express-utils,由InversifyJS提供支持。

    【讨论】:

    • 不错!我喜欢这种方法。如果你不介意,我确实有几个问题。在这种情况下,您的 server.ts 文件需要如何设置以适应这种方法,尤其是如果您还需要诸如 winston 日志记录等中间件项目时?这也会如何影响您的 bin/www 文件?
    • 有几个例子here可以作为参考。我没有 Express 4 的示例,但我认为它应该是兼容的。
    • 我终于把所有东西都转移到了 inversify-express-utils 但是有一些我遇到了问题,非常感谢你的意见。 1)对于上面的示例,您如何将模型绑定到容器?对于我的场景,作为背景,我目前将我的模型作为“Model”注入到“Model”对象类型的存储库中。 2)在此调用之前您如何建立数据库连接:let server = new InversifyExpressServer(container)?
    • Document 让我认为您正在使用mongodb?如果是这样,这里有一个演示 github.com/stelltec/public-tech-demos/tree/master/…
    猜你喜欢
    • 1970-01-01
    • 2020-12-12
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    • 2020-03-14
    • 2013-03-03
    • 1970-01-01
    相关资源
    最近更新 更多