扩展配置类
针对各种扩展的情况,我们提供了通用的高级能力,目前是通过固定的 src/configuration.ts
文件来实现的,此文件为特殊规范,目前无法改变文件名。
例如:
base-app
├── package.json
└── src
├── configuration.ts
└── lib
└── userManager.ts
此文件为一个特殊类,类名随意,通过 @Configuration
修饰。
// src/configuration.ts
import { Configuration } from '@midwayjs/decorator';
@Configuration({
imports: [],
importObjects: []
})
export class ContainerLifeCycle {
}
@Configuration
的能力非常多,提供了扩展 IoC 容器的能力,该文件也是后期扩展容器生命周期的核心文件。
函数配置
当代码逻辑变多的时候,特别是跨环境时,我们就需要传统的配置能力。
我们可以针对不同环境创建配置文件,文件内容为 JSON 格式,目录结构如下。
base-app
├── package.json
└── src
├── configuration.ts
└── config
└── 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
都会被扫描加载。
// src/configuration.ts
import { Configuration } from '@midwayjs/decorator';
@Configuration({
importConfigs: [
'./config/',
]
})
export class ContainerLifeCycle {
}
或者手动指定一批文件。
// src/configuration.ts
import { Configuration } from '@midwayjs/decorator';
@Configuration({
importConfigs: [
'./config/config.default',
'./config/config.local'
]
})
export class ContainerLifeCycle {
}
配置格式
配置文件格式基本为 json,也可以通过函数返回,编写逻辑。
比如:
// config.default.ts
export = {
userService: {
appname: 'test'
}
};
或者支持回调方式。
// config.default.ts
export = () => {
return {
userService: {
appname: 'test'
},
};
};
可以使用 @Config
装饰器注入。
import { Config } from '@midwayjs/decorator';
export class IndexHandler {
@Config('userService')
userConfig;
async handler() {
console.log(this.userConfig.appname); // test
}
}
配置加载顺序
配置存在优先级(应用代码 > 框架 > 扩展),相对于此运行环境的优先级会更高。
比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。
-> 扩展 config.default.ts
-> 框架 config.default.ts
-> 应用 config.default.ts
-> 扩展 config.prod.ts
-> 框架 config.prod.ts
-> 应用 config.prod.ts
配置生命周期
在通常情况下,我们希望在应用启动的时候做一些初始化、或者其他一些预处理的事情,比如创建数据库连接、预生成一些配置,而不是在请求响应时去处理。
通过 src/configuration.ts
文件,导出的类实现 ILifeCycle 接口,就可以在应用 ready 的时候处理这类需求。
接口定义如下。
interface ILifeCycle {
/**
* 在应用 ready 的时候执行
* @param container IoC 容器
*/
onReady(container?: IMidwayContainer): Promise<void>;
/**
* 在应用停止的时候执行
* @param container IoC 容器
*/
onStop?(container?: IMidwayContainer): Promise<void>;
}
举个例子。
我们需要在初始化时提前连接一个数据库,由于在类中,所以也可以通过 @Inject
装饰器注入 db 这样一个数据库的连接工具类,这个实例包含 connect 和 close 两个函数:
@Configuration({
// 一些配置,见 Configuration 说明
imports: [
'../../midway-plugin-mock/src',
'../../midway-plugin-ok/src'
],
importObjects: {
aa: 123
}
})
class ContainerConfiguration implements ILifeCycle {
@Inject()
db: any;
async onReady(container: IMidwayContainer): Promise<void> {
// 建立数据库连接
await this.db.connect();
}
async onStop(): Promise<void> {
// 关闭数据库连接
await this.db.close();
}
}
这样,我们就能够在应用启动时建立数据库连接,而不是在请求响应时再去创建。同时,在应用停止时,也可以优雅的关闭数据库连接。
除此之外,通过这个方式,可以对默认注入的对象做扩充。
import * as sequelize from 'sequelize';
@Configuration()
class ContainerConfiguration implements ILifeCycle {
async onReady(container: IMidwayContainer): Promise<void> {
// 三方包对象
container.registerObject('sequelize', sequelize);
}
}
在其他的类中可以直接注入使用。
export class IndexHandler {
@Inject()
sequelize;
async handler() {
console.log(this.sequelize);
}
}