开启掘金成长之旅!这是我参与「掘金日新计划 · 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时,就会触发自身的装饰器(包括方法装饰器以及类装饰器等),实例化的工作将在这些装饰器的处理函数中进行