依赖注入(Dependency Injection)
核心概念
在 awe-axios 中,依赖注入(DI)通过 @Inject 装饰器与 IoC(控制反转)容器实现,用于解耦组件间的依赖关系,自动管理实例的创建和注入过程。以下是详细实现方式和使用说明:
基本使用
@Inject 支持多种配置方式,满足不同场景的依赖查找需求:
字符串表达式注入
格式:[模块名.]别名(模块名可选,默认模块为 __default__)
// 注入默认模块的 "userService"
@Inject('userService')
private userService: UserService;
// 注入 "api" 模块的 "productApi"
@Inject('api.productApi')
private productService: ProductService;配置对象注入
当然你也可以通过配置对象来实现注入查找,配置对象结构为:
type GetInstanceConfig = {
/**
* 模块名
*/
module?: string | symbol;
/**
* 别名
*/
alias?: string;
/**
* 构造器
*/
ctor?: DecoratorClass;
/**
* 创建实例模式
*/
scope: InstanceScope | string;
/**
* 备份列表
*/
backups?: InjectBackups;
};如下示例:
// 通过类查找(最常用,类型安全)
@Inject({ ctor: UserService })
private userService: UserService;
// 通过模块+别名查找
@Inject({ module: 'api', alias: 'productApi' })
private productService: ProductService;当同时配置了 ctor 和 alias 时
如果你同时配置了 ctor 和 alias , awe-axios会只使用 module + ctor 来进行查找,并忽略 alias 。
关于scope和backups
scope 配置控制依赖实例的创建策略,默认值为 SINGLETON,backups 配置指定备选实例。后续会详细讲解
构造函数直接注入
当然你也可以直接传入类作为参数(等价于 { ctor: 类 }):
@Inject(UserService)
private userService: UserService;实例作用域
awe-axios在实例注入时提供了多种实例注入方式,包括单例模式、瞬时模式、原型模式、浅克隆模式等,这些模式可以满足不同场景的需求。通过 scope 配置控制依赖实例的创建策略,默认值为 SINGLETON:
| 作用域 | 说明 | 适用场景 |
|---|---|---|
SINGLETON | 单例模式,全局唯一实例 | 工具类、配置服务 |
TRANSIENT | 瞬时模式,每次注入创建新实例 | 有状态的对象、请求上下文 |
PROTOTYPE | 原型模式,基于原实例创建新对象 | 需要继承原实例状态的场景 |
SHALLOWCLONE | 浅克隆模式,复制原实例的表层属性 | 简单对象的快速复制 |
DEEPCLONE | 深克隆模式,完全复制原实例 | 复杂对象的独立副本 |
瞬时模式
瞬时模式下每次注入都会创建一个新的实例,awe-axios默认采用瞬时模式注入,如下示例:
@Component()
class User {}
class UserService {
@Inject(User)
user1!: User;
@Inject({
module: '__default__',
alias: 'user',
scope: 'TRANSIENT',
})
user2!: User;
}
let userService = new UserService();
// 由于默认采用的瞬时模式,所以两个注入的 user 实例是不同的
console.log(userService.user1 === userService.user2); // false单例模式
单例模式下每次注入都会返回同一个实例,如下示例:
@Component()
class User {}
class UserService {
@Inject({
ctor: User,
scope: 'SINGLETON',
})
user1!: User;
@Inject({
module: '__default__',
alias: 'user',
scope: 'SINGLETON',
})
user2!: User;
}
let userService = new UserService();
// 由于默认采用的单例模式,所以两个注入的 user 实例是同一个
console.log(userService.user1 === userService.user2); // true原型模式
原型模式下每次注入都会创建一个以该类实例为原型的新实例,如下示例:
@Component()
class User {}
class UserService {
@Inject({
ctor: User,
scope: 'PROTOTYPE',
})
user1!: User;
}
let userService = new UserService();
// user1 以 User类实例为原型
console.log(userService.user1 instanceof User); // true
console.log(Object.getPrototypeOf(userService.user1)); // User {}浅克隆模式
浅克隆模式下每次注入都会创建一个新的实例,但只复制原实例的表层属性,如下示例:
@Component()
class User {
obj: any = { a: 1 };
}
class UserService {
@Inject({
ctor: User,
scope: 'SINGLETON',
})
user1!: User;
@Inject({
ctor: User,
scope: 'SHALLOWCLONE',
})
user2!: User;
}
let userService = new UserService();
// 改变user1的obj中的a属性
userService.user1.obj.a = 2;
// 由于采用的是浅克隆,所以user2的obj中的a属性也会随之改变
console.log(userService.user2.obj.a); // 2深克隆模式
深克隆模式下每次注入都会创建一个新的实例,但会递归复制原实例的所有属性,如下示例:
@Component()
class User {
obj: any = { a: 1 };
}
class UserService {
@Inject({
ctor: User,
scope: 'SINGLETON',
})
user1!: User;
@Inject({
ctor: User,
scope: 'DEEPCLONE',
})
user2!: User;
}
let userService = new UserService();
// 改变user1的obj中的a属性
userService.user1.obj.a = 2;
// 由于采用的是深克隆,所以user2的obj中的a属性不会随之改变
console.log(userService.user2.obj.a); //1依赖备选
为了保证注入的稳定性,awe-axios提供了依赖备选机制,当主实例查找失败时,可通过 backups 配置指定备选实例,backups 配置可以是一个构造器或一个对象或构造器和对象组成的数组,如下示例:
class User {
obj: any = { a: 1 };
}
class Student {}
class UserService {
@Inject({
alias: 'person',
backups: [User, Student],
// 或
// backups: [new User(), new Student()]
// 或
// backups: User
})
user1!: User;
}
let userService = new UserService();
// 没有person实例,所以采用备用User类作为实例 User { obj: { a: 1 } }
console.log(userService.user1);备选顺序
当备选实例有多个时,awe-axios会按注册顺序依次尝试,直到找到实例为止。如果没有则注入 undefined。