优化依赖注入性能
- 避免循环依赖
- 思路:
- 在依赖注入容器中,维护一个记录正在解析的依赖的栈。当解析一个新的依赖时,将其添加到栈中。如果在解析过程中发现当前依赖已经在栈中,就说明存在循环依赖。
- 采用深度优先搜索(DFS)的方式解析依赖。从顶层依赖开始,递归地解析其所有依赖,在这个过程中检查循环。
- 关键代码示例(简化示意):
class DependencyContainer {
private resolvingStack: string[] = [];
private dependencies: { [key: string]: () => any } = {};
register(key: string, factory: () => any) {
this.dependencies[key] = factory;
}
resolve(key: string): any {
if (this.resolvingStack.includes(key)) {
throw new Error(`Circular dependency detected for ${key}`);
}
this.resolvingStack.push(key);
const factory = this.dependencies[key];
if (!factory) {
throw new Error(`Dependency ${key} not registered`);
}
const result = factory();
this.resolvingStack.pop();
return result;
}
}
- 其他性能优化
- 延迟加载:
- 思路:只有在真正需要某个依赖时才进行实例化。可以通过使用工厂函数来实现,在
resolve
方法中调用工厂函数来创建实例,而不是在注册依赖时就创建。
- 关键代码示例:
class DependencyContainer {
//... 其他代码
resolve(key: string): any {
const factory = this.dependencies[key];
if (!factory) {
throw new Error(`Dependency ${key} not registered`);
}
return factory();
}
}
// 注册依赖
container.register('service', () => new Service());
利用装饰器实现切面编程(AOP)
- 日志记录
- 思路:创建一个日志装饰器,该装饰器在目标方法执行前后记录日志信息。可以通过反射获取方法的名称等信息,然后使用
console.log
或日志库记录日志。
- 关键代码示例:
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling method ${propertyKey} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`Method ${propertyKey} returned:`, result);
return result;
};
return descriptor;
}
class MyService {
@log
public myMethod(a: number, b: number) {
return a + b;
}
}
- 权限验证
- 思路:创建一个权限验证装饰器,该装饰器可以从当前上下文(例如通过一个全局的用户信息对象)获取用户权限,然后判断用户是否有权限执行目标方法。如果没有权限,抛出一个错误或返回一个提示信息。
- 关键代码示例:
interface User {
permissions: string[];
}
let currentUser: User = { permissions: ['view'] };
function checkPermission(requiredPermission: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
if (!currentUser.permissions.includes(requiredPermission)) {
throw new Error('Permission denied');
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
class Resource {
@checkPermission('edit')
public editResource() {
console.log('Resource edited');
}
}