开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
设计
前置组件、或者中间件定义为,请求正式进入controller之前,需要执行的中间件。比如,jwt校验,跨域处理等。
设计一个前置组件装饰器,接受两个参数:排序和名称,扫描时,将其实例化并保持到相应的缓存中。
@PreComponent
在完成ws服务的部署之后,进行前置组件的依次调用,加载如express中
实现
1.装饰器@PreComponent的实现
export const PreComponent = (index: number = 100, componentName?: string): ClassDecorator => {
return (constructor: any) => {
let id = getTargetId(constructor)
if (!componentName) {
componentName = constructor.name + '_' + id
}
constructor.prototype.index = index
constructor.prototype.name = constructor.name
Reflect.defineMetadata('preComponent', constructor.name, constructor);
log(`[PreComponent]- add PreComponent: ${constructor.name}`)
// 可直接new一个不需要代理
const instance = proxify(new constructor());
application.componentManager.addPreComponents(componentName, instance)
application.componentManager.addBean(componentName, constructor, instance)
};
}
将实例保存至两个集合中,方便后续获取依赖等操作
2.相关保存实例的方法
// class
export class ComponentManager {
preComponents?: Map<string, ComponentInfo> = new Map(); // 添加Controller之前需要添加的组件集合
componentsOnName?: Map<string, ComponentInfo> = new Map(); // 普通组件集合
componentsOnKey?: Map<any, ComponentInfo> = new Map(); // 普通组件集合
injectInfos: Map<string, InjectInfo[]> = new Map();
...
}
/////
/**
*
* @param componentName 组件名称
* @param originClass 组件class
* @param instance 组件实例
*/
public async addBean(componentName: string, originClass: any, instance: any) {
let _componentName;
componentName = ((_componentName = componentName) !== null && _componentName !== void 0 ? _componentName : originClass.name);
let component = {
className: originClass.name,
componentName,
status: 'wired',
value: originClass,
instance: instance,
};
//autoWiringComponents[originClass] = autoWiringComponents[componentName]
this.addComponents(componentName, component)
log(`[Component]-load component:${componentName} ${originClass.name}`)
}
//////
public async addPreComponents(name: string, con: any) {
this.preComponents.set(name, con)
}
3.加载组件
public loadPreComponents(app): void {
log(`========================= load preComponent========================`)
let array = []
for (let [key, value] of this.preComponents.entries()) {
// log(key)
array.push(value)
}
// 从小到大的排序
array.sort((Acomponent, Bcomponent) => {
return Acomponent.index - Bcomponent.index;
});
//
array.forEach(component => {
log(`[preComponent]- load preComponent: ${component.name}`)
if (component && component.enable) {
component.enable(app)
}
})
}
默认是调用组件实例的enable方法,将express app当做参数插入 例如,配置app服务的请求配置
@PreComponent(0)
class WebConfig{
enable(app){
log(`[WebConfig]- enable WebConfig`)
app.use(cookieparser());
// 中间件
app.use(express.json({ limit: '5mb' }));
app.use(express.urlencoded({ extended: true }));
// let s_path = path.join(process.cwd(), 'ui/dist')
// app.use(express.static(s_path));
app.options('*', function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Authorization,X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
});
}
}