扩展配置类

针对各种扩展的情况,我们提供了通用的高级能力,目前是通过固定的 src/configuration.ts 文件来实现的,此文件为特殊规范,目前无法改变文件名。

例如:

  1. base-app
  2. ├── package.json
  3. └── src
  4. ├── configuration.ts
  5. └── lib
  6. └── userManager.ts

此文件为一个特殊类,类名随意,通过 @Configuration 修饰。

  1. // src/configuration.ts
  2. import { Configuration } from '@midwayjs/decorator';
  3. @Configuration({
  4. imports: [],
  5. importObjects: []
  6. })
  7. export class ContainerLifeCycle {
  8. }

@Configuration 的能力非常多,提供了扩展 IoC 容器的能力,该文件也是后期扩展容器生命周期的核心文件。

函数配置

当代码逻辑变多的时候,特别是跨环境时,我们就需要传统的配置能力。

我们可以针对不同环境创建配置文件,文件内容为 JSON 格式,目录结构如下。

  1. base-app
  2. ├── package.json
  3. └── src
  4. ├── configuration.ts
  5. └── config
  6. └── config.default.ts

我们需要在 configuration.ts 中配置需要依赖的环境文件。

  • 1、文件以相对路径存在,目录结构随意自定,推荐传统的 config/
  • 2、文件指定无需 ts 后缀
  • 3、目前配置文件必须指定添加
  • 4、合并规则,在 NODE_ENV=** 环境下,会加载 **/config.defaut.ts 的文件以及 **/config.{env}.ts 文件。

比如,下面代码在本地会加载 config.default.*config.local.* 文件,但是如果在其他环境,只会加载 config.default.*

:::info importConfigs 这里只是指定需要加载的文件,实际运行时会自动选择当前的环境来找对应的文件后缀。 :::

可以指定加载一个目录,目录里所有的 config.*.ts 都会被扫描加载。

  1. // src/configuration.ts
  2. import { Configuration } from '@midwayjs/decorator';
  3. @Configuration({
  4. importConfigs: [
  5. './config/',
  6. ]
  7. })
  8. export class ContainerLifeCycle {
  9. }

或者手动指定一批文件。

  1. // src/configuration.ts
  2. import { Configuration } from '@midwayjs/decorator';
  3. @Configuration({
  4. importConfigs: [
  5. './config/config.default',
  6. './config/config.local'
  7. ]
  8. })
  9. export class ContainerLifeCycle {
  10. }

配置格式

配置文件格式基本为 json,也可以通过函数返回,编写逻辑。

比如:

  1. // config.default.ts
  2. export = {
  3. userService: {
  4. appname: 'test'
  5. }
  6. };

或者支持回调方式。

  1. // config.default.ts
  2. export = () => {
  3. return {
  4. userService: {
  5. appname: 'test'
  6. },
  7. };
  8. };

可以使用 @Config 装饰器注入。

  1. import { Config } from '@midwayjs/decorator';
  2. export class IndexHandler {
  3. @Config('userService')
  4. userConfig;
  5. async handler() {
  6. console.log(this.userConfig.appname); // test
  7. }
  8. }

配置加载顺序

配置存在优先级(应用代码 > 框架 > 扩展),相对于此运行环境的优先级会更高。

比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。

  1. -> 扩展 config.default.ts
  2. -> 框架 config.default.ts
  3. -> 应用 config.default.ts
  4. -> 扩展 config.prod.ts
  5. -> 框架 config.prod.ts
  6. -> 应用 config.prod.ts

配置生命周期

在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。

通过 src/configuration.ts 文件,导出的类实现 ILifeCycle 接口,就可以在应用 ready 的时候处理这类需求。

接口定义如下。

  1. interface ILifeCycle {
  2. /**
  3. * 在应用 ready 的时候执行
  4. * @param container IoC 容器
  5. */
  6. onReady(container?: IMidwayContainer): Promise<void>;
  7. /**
  8. * 在应用停止的时候执行
  9. * @param container IoC 容器
  10. */
  11. onStop?(container?: IMidwayContainer): Promise<void>;
  12. }

举个例子。

我们需要在初始化时提前连接一个数据库,由于在类中,所以也可以通过 @Inject 装饰器注入 db 这样一个数据库的连接工具类,这个实例包含 connect 和 close 两个函数:

  1. @Configuration({
  2. // 一些配置,见 Configuration 说明
  3. imports: [
  4. '../../midway-plugin-mock/src',
  5. '../../midway-plugin-ok/src'
  6. ],
  7. importObjects: {
  8. aa: 123
  9. }
  10. })
  11. class ContainerConfiguration implements ILifeCycle {
  12. @Inject()
  13. db: any;
  14. async onReady(container: IMidwayContainer): Promise<void> {
  15. // 建立数据库连接
  16. await this.db.connect();
  17. }
  18. async onStop(): Promise<void> {
  19. // 关闭数据库连接
  20. await this.db.close();
  21. }
  22. }

这样,我们就能够在应用启动时建立数据库连接,而不是在请求响应时再去创建。同时,在应用停止时,也可以优雅的关闭数据库连接。

除此之外,通过这个方式,可以对默认注入的对象做扩充。

  1. import * as sequelize from 'sequelize';
  2. @Configuration()
  3. class ContainerConfiguration implements ILifeCycle {
  4. async onReady(container: IMidwayContainer): Promise<void> {
  5. // 三方包对象
  6. container.registerObject('sequelize', sequelize);
  7. }
  8. }

在其他的类中可以直接注入使用。

  1. export class IndexHandler {
  2. @Inject()
  3. sequelize;
  4. async handler() {
  5. console.log(this.sequelize);
  6. }
  7. }