node.js:在 app.js 中注入依赖项

node.js: injecting dependencies in app.js

我正在使用 node.js 和打字稿开发应用程序。我按照本文 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 是单线程的。

Does this mean each person making a request will receive a different service and repository or the same instance

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

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

I would imagine it being better if each user receives a different instance.

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

How would this effect the database calls being made in the repository layer?

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

app.js、server.js

之间的关系

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

and requests being made as node.js is single threaded

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

另一种方法

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

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

相反,您可以声明一个 class 及其要注入的依赖项:

@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 enpoint 的控制器的真实示例:

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 and it is powered by InversifyJS