nestjs启动流程概览

一般的启动脚本是这样的

import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';
import { ValidationPipe } from './common/pipes/validation.pipe';

async function bootstrap() {
  const app = await NestFactory.create(ApplicationModule);
  await app.listen(3000);
}
bootstrap();

第一步:创建NestApplication实例

src.core/nest-factory.ts

 //创建一个NestApplication实例,使用指定根模块类,与Express对象
    public async create(module, express = ExpressAdapter.create()): Promise {
        //初始化根模块,进行模块依赖的提取、实例化
        await this.initialize(module);
        //创建应用程序类,返回一个代理对象,可以捕捉异常,打印异常
        return this.createNestInstance(
            //一个应用程序类,使用容器、express创建
            new NestApplication(this.container, express),
        );
    }

//创建所有的nest实例
    private createNestInstance(instance: T) {
        //创建代理对象
        return this.createProxy(instance);
    }

//创建指定实例的代理
    private createProxy(target) {
        //创建处理函数
        const proxy = this.createExceptionProxy();
        //创建代理对象,get、set操作都被处理函数拦截
        return new Proxy(target, {
            get: proxy,
            set: proxy,
        });
    }

    //创建处理函数
    private createExceptionProxy() {
        //receiver是被代理的实例,prop为要访问或者设置的属性名
        return (receiver, prop) => {
            //如果属性不存在直接返回
            if (!(prop in receiver))
                return;

                //如果属性为函数
            if (isFunction(receiver[prop])) {
                //返回新函数
                return (...args) => {
                    let result;
                    //在异常区内同步运行,这个区可以捕捉异常
                    ExceptionsZone.run(() => {
                        //运行原有函数
                        result = receiver[prop](...args);
                    });
                    return result;
                };
            }
            //返回源属性或者新函数
            return receiver[prop];
        };
    }

//初始化模块
    private async initialize(module) {
        try {
            //打印应用程序启动信息
            this.logger.log(messages.APPLICATION_START);
            //在异常区异步运行
            await ExceptionsZone.asyncRun(async () => {
                //使用依赖扫描器扫描模块,获取所有关联模块、控制器、组件,并且存储他们
                this.dependenciesScanner.scan(module);
                //使用实例加载器创建依赖的实例
                await this.instanceLoader.createInstancesOfDependencies();
            });
        }
        //遇到异常取消进程
        catch (e) {
            process.abort();
        }
    }
创建NestApplication实例也分为两步:

1.初始化模块:在可捕获异常区域中进行依赖扫描、实例加载

2.创建Nest实例:创建一个可捕获异常代理的实例

特点:初始化时的方法调用、创建的Nest实例方法都是在一个异常区域中运行的,出现的异常会被框架处理

第二部:启动监听

src/core/nest-application.ts

//重载监听方法
    public async listen(port: number, callback?: () => void);
    public async listen(port: number, hostname: string, callback?: () => void);
    //实现监听方法
    public async listen(port: number, ...args) {
        //如果未初始化先初始化
        (!this.isInitialized) && await this.init();
        //使用内部的原生服务器实例监听端口,这个实例使用express构造
        this.httpServer.listen(port, ...args);
        return this.httpServer;
    }

 //初始化方法
    public async init() {
        //设置解析中间件
        this.setupParserMiddlewares();
        //设置模块,即Socket、中间件、微服务模块
        await this.setupModules();
        await this.setupRouter();
        //调用初始化钩子
        this.callInitHook();
        this.logger.log(messages.APPLICATION_READY);
        //修改标志
        this.isInitialized = true;
    }

    //设置解析中间件,这个中间件并不是那个意思
    public setupParserMiddlewares() {
        const parserMiddlewares = {
            //json解析器
            jsonParser: bodyParser.json(),
            //urlencoded编码解析器
            urlencodedParser: bodyParser.urlencoded({ extended: true }),
        };
        //遍历,过滤出没使用的中间件,添加到express上
        Object.keys(parserMiddlewares)
            .filter((parser) => !this.isMiddlewareApplied(this.express, parser))
            .forEach((parserKey) => this.express.use(parserMiddlewares[parserKey]));
    }

  //设置模块,中间件、socket、微服务
    public async setupModules() {
        //设置SocketModule,将容器与配置传递给它
        this.socketModule && this.socketModule.setup(this.container, this.config);
        //设置微服务模块,还是将容器与配置传递给它
        if (this.microservicesModule) {
            this.microservicesModule.setup(this.container, this.config);
            this.microservicesModule.setupClients(this.container);
        }
        //设置中间件模块,这一步调用了模块实例的configure方法,生成了中间件配置信息,存储到了中间件容器中
        await this.middlewaresModule.setup(
            this.middlewaresContainer,
            this.container,
            this.config,
        );
    }

//设置路由
    public async setupRouter() {
        //创建mergeParams: true 路由
        const router = ExpressAdapter.createRouter();
        //为创建的路由设置中间件,根据上面得到的中间件容器中的配置信息
        await this.setupMiddlewares(router);
        //解析路由,将得到的执行上下文方法与路由路径关联到router对象上,执行上下文包含了参数注入、Guard、拦截器、Pipe、异常过滤器等功能
        this.routesResolver.resolve(router);
        //为路由对象加上全局前缀,设置到express实例上,router对象上所有路由路径都会加上这个统一前缀
        this.express.use(validatePath(this.config.getGlobalPrefix()), router);
    }

在listen方法中对NestApplication实例进行初始化,分为以下步骤

1.设置请求解析中间件:对所有路由设置了两个请求解析中间件,application/json与application/x-www-form-urlencoded这两个MIME类型的请求体会被解析,也就是说这两个类型请求获取不到原始请求体,req.body中直接就是对象

2.设置模块:这里的模块不是Module实例,而是内置的模块,有三个:Middleware、WebSocket、Microservices三个模块,分别管理了中间件、websocket、微服务三个功能,这一步设置模块主要是初始化了相应的模块
3.设置路由:这一步就是解析控制器中的路由方法,设置到express实例上,并且设置了中间件
当NestApplication实例初始化完成后,启动express实例的监听




你可能感兴趣的:(nest.js)