Introduction to nestjs
代码分析
入口main.ts
import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
await app.listen(3000);
}
bootstrap();
NestFactory构造
public async create(
module: any,
serverOrOptions?: any,
options?: NestApplicationOptions,
): Promise<
INestApplication & (INestExpressApplication | INestFastifyApplication)
> {
const isHttpServer = serverOrOptions && serverOrOptions.patch;
// tslint:disable-next-line:prefer-const
let [httpServer, appOptions] = isHttpServer
? [serverOrOptions, options]
: [ExpressFactory.create()/* 默认使用Express*/, serverOrOptions];
const applicationConfig = new ApplicationConfig();
const container = new NestContainer(applicationConfig);//生成容器container;传入了配置对象
httpServer = this.applyExpressAdapter(httpServer);//初始化http服务
this.applyLogger(appOptions);//日志输出对象
await this.initialize(module, container, applicationConfig, httpServer);
return this.createNestInstance<NestApplication>(
new NestApplication(container, httpServer, applicationConfig, appOptions),
);
}
- 第一个参数是使用是传入的类似angularmodule的对象
- 第二个参数可以是设置参数,也可以是类似express的MVC,如官网提到的fastify,覆盖默认使用的express
- 第三个参数就是设置参数
初始化模块
private async initialize(
module,
container: NestContainer,
config = new ApplicationConfig(),
httpServer: HttpServer = null,
) {
//生成实例加载器和依赖扫描器
const instanceLoader = new InstanceLoader(container);
const dependenciesScanner = new DependenciesScanner(
container,
new MetadataScanner(),
config,
);
container.setApplicationRef(httpServer);
try {
this.logger.log(messages.APPLICATION_START);
await ExceptionsZone.asyncRun(async () => {
await dependenciesScanner.scan(module);
await instanceLoader.createInstancesOfDependencies();
dependenciesScanner.applyApplicationProviders();
});
} catch (e) {
process.abort();
}
}
扫描当前文件的依赖
public async scan(module: Type<any>) {
await this.scanForModules(module);
await this.scanModulesForDependencies();
this.container.bindGlobalScope();
}
scanForModules扫描及保存模块(包括imports进来的模块)
public async scanForModules(
module: Type<any> | DynamicModule,
scope: Type<any>[] = [],
) {
await this.insertModule(module, scope);
const modules = this.reflectMetadata(module, metadata.MODULES);
for (const innerModule of modules) {
await this.scanForModules(innerModule, [].concat(scope, module));
}
}
容器对象的insertModule
public async insertModule(
metatype: Type<any> | DynamicModule | Promise<DynamicModule>,
scope: Type<any>[],
): Promise<Module> {
if (!metatype) {
throw new InvalidModuleException(scope);
}
//模块编译器先编译模块
const { type, dynamicMetadata, token } = await this.moduleCompiler.compile(
metatype,
scope,
);
//根据token判断是否已保存。没有保存则创建一个Module实例。
if (this.modules.has(token)) {
return;
}
//Module对象能保存组件、注入的服务、路由、导出的对象及相关模块。创建时先保存核心的注入(模块的实例,模块的配置、映射器、MVC对象、外部的上下文生成器、该模块的的所有模块)
const module = new Module(type, scope, this);
this.modules.set(token, module);
//动态模块保存在dynamicModulesMetadata对象中,然后对动态模块里的模块(modules\imports)都执行下addModule方法,共用一个作用域数组
this.addDynamicMetadata(token, dynamicMetadata, [].concat(scope, type));
//全局模块则添加到globalModules的Set对象中
this.isGlobalModule(type) && this.addGlobalModule(module);
return module;
}
扫描模块里的依赖项,作依赖注入的准备工作,其实就是处理Module的配置项await this.scanModulesForDependencies();
async scanModulesForDependencies() {
const modules = this.container.getModules();
for (const [token, { metatype }] of modules) {
await this.reflectImports(metatype, token, metatype.name);
this.reflectProviders(metatype, token);
this.reflectControllers(metatype, token);
this.reflectExports(metatype, token);
}
this.calculateModulesDistance(modules);
}