[Typescript]用装饰器封装Express服务(3)-组件扫描

101 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

设计

组件扫描是在application上下文实例化完成之后进行的,所要做的事情是,根据先前传入或者系统默认的路径,依次向下查找,import各个js,ts,或者mjs,cjs等文件,并根据其所带的注解类型不同,实例化并添加到application上下文的不同缓存中,以备后续的各个系统动作所能获取到。这些缓存包括,aop缓存,普通组件缓存,前置中间件缓存,ws服务缓存,controller缓存等,当然,还可以设计加上过滤器以及拦截器等缓存,以及实际的业务要求添加即可。

扫描的路径参数方面,其他优秀的框架组件中,使用了正则以及通用路径匹配等多种方式。不过,笔者这里,简单地使用以及目录向下查找的简单方式。如,传入的是

scanPath:['/busi','/scan']

那么。会以./busi和./sys为起点向下递归检索各个子目录。

实现

首先,组件查询方法是application上下文对象的一个方法

 application.scanBean()
 
 //
 public async scanBean() {
    console.log(`========================= scan allComponent========================`)
    // 项目入口目录
    let rootPath = process.cwd()
    await Promise.all(this.scanPath.map(async p => {
        await this.readDir((rootPath + "/" + p).replace('//', '/'), rootPath);
    })).then(result => {
        console.log('scan finish')
    }).catch(err => {
        console.error(err)
    })
}

首先循环scanPath数组,然后在循环内调用递归函数readDir

而递归函数readDir则是具体检索各个目录的方法

 application.readDir(dirPath: string, _rootPath: string)
 
 //
public async readDir(dirPath: string, _rootPath: string) {
    try {
        // console.log(dirPath)
        let b = fs.existsSync(dirPath)
        if (!b) return
        let files = fs.readdirSync(dirPath)
        for (let i in files) {
            let fileName = files[i]
            // console.log(fileName)
            let _path = path.join(dirPath, fileName)
            try {
                let stat = fs.statSync(_path);
                if (stat.isFile()) {
                    if (fileName == 'app.js' || fileName == 'app.ts' || fileName == 'ioc.ts' || fileName.indexOf('.') == 0) {
                        // 忽略文件
                    } else if (/\.(js|ts|mjs)$/.test(fileName)) {
                        await import(_path)
                    }
                } else if (/(\.git|ui|dist|core|node_modules)/.test(fileName)) {

                } else if (stat.isDirectory()) {
                    // console.log("isDirectory")
                    await this.readDir(_path, _rootPath)
                }
            } catch (e) {
                console.error(e)
            }
        }
    } catch (err) {
        console.error(err)
    }

}

当文件被import时,就会触发自身的装饰器(包括方法装饰器以及类装饰器等),实例化的工作将在这些装饰器的处理函数中进行