生命周期
简介
本库的生命周期包括两个阶段:激活(Activation) 和 销毁(Deactivation)。
- 激活阶段:在
container.get(token)首次解析服务时触发,涉及Binding#onActivation、Container#onActivation和@PostConstruct三个钩子。 - 销毁阶段:在调用
container.unbind(token)/container.unbindAll()/container.destroy()时触发,涉及Container#onDeactivation、Binding#onDeactivation和@PreDestroy三个钩子。
激活顺序
本库激活顺序
Binding#onActivation → Container#onActivation → @PostConstructinversify 激活顺序
@PostConstruct → Binding#onActivation → Container#onActivation设计原因
本库将 @PostConstruct 放在最后执行,是因为 @PostConstruct 方法中通常需要访问通过 @Inject 装饰的属性。
属性注入(_getInjectProperties)发生在 activation 阶段之后。如果 @PostConstruct 在 activation 之前执行,此时注入的属性还未就绪,会导致 @PostConstruct 中访问注入属性时得到 undefined。
已知限制
activation handler(Binding#onActivation 和 Container#onActivation)中不能访问注入的属性,因为此时属性注入还未完成。
销毁顺序
本库与 inversify 的销毁顺序相同:
Container#onDeactivation → Binding#onDeactivation → @PreDestroy触发时机
container.unbind(token):解绑指定 token,触发该 token 对应服务的销毁流程container.unbindAll():解绑当前容器中所有 tokencontainer.destroy():递归销毁所有子容器,并解绑当前容器中所有 token
@PostConstruct 继承行为
沿继承链向上查找,执行第一个找到的 @PostConstruct 方法,找到即停止。
场景一:A 继承 B,A 和 B 都有 @PostConstruct
只执行 A 的 @PostConstruct,B 的不执行。
@Injectable()
class B {
@PostConstruct()
init() {
console.log('B init'); // 不会执行
}
}
@Injectable()
class A extends B {
@PostConstruct()
init() {
console.log('A init'); // 只执行这个
}
}场景二:A 继承 B,只有 B 有 @PostConstruct
执行 B 的 @PostConstruct。
@Injectable()
class B {
@PostConstruct()
init() {
console.log('B init'); // 会执行
}
}
class A extends B {
// A 没有 @PostConstruct
}场景三:A 继承 B 继承 C,A 和 B 都没有 @PostConstruct
执行 C 的 @PostConstruct。
@Injectable()
class C {
@PostConstruct()
init() {
console.log('C init'); // 会执行
}
}
class B extends C {
// B 没有 @PostConstruct
}
class A extends B {
// A 没有 @PostConstruct
}使用限制
@PostConstruct
@PostConstruct 只能在类中使用,这是显然的,同时也只能等待其他异步类,也就是依赖的类也使用了@PostConstruct。
此时当前类会等待所有依赖类完成之后才会执行自己的@PostConstruct。
也就是说如果当前类还有其他类型的依赖,比如有些依赖是通过 toConstantValue、toDynamicValue 绑定的服务,@PostConstruct 是不会等待它们完成。 就算toDynamicValue本身是返回了一个promise。
const container = new Container();
// ✅ @PostConstruct 生效
container.bind(MyService).toSelf();
// ❌ @PostConstruct 不生效
container.bind(TOKEN).toConstantValue(new MyService());
container.bind(TOKEN).toDynamicValue(() => new MyService());@LazyInject
@LazyInject 的自动容器查找要求宿主类(即使用 @LazyInject 的那个类)必须通过 to() 或 toSelf() 注册到容器中,并且通过 container.get() 获取实例。只有这样,容器才能在内部建立实例到容器的映射关系,使得 @LazyInject 能够自动找到正确的容器来解析依赖。
如果宿主类不在依赖注入体系内(例如 React 类组件等由第三方框架实例化的类,或者手动 new 出来的实例),容器无法自动识别该实例属于哪个容器,此时必须显式传入 container 参数。
// ✅ 宿主类 A 通过 toSelf() 注册,自动查找容器
class A {
@LazyInject(MyService)
service: MyService;
}
container.bind(A).toSelf();
container.bind(MyService).toSelf();
const a = container.get(A); // a.service 可以自动解析
// ❌ 宿主类不在依赖注入体系内(如 React 类组件),需显式传入 container
class MyReactComponent {
@LazyInject(MyService, container)
service: MyService;
}完整生命周期流程
container.get(token) 首次调用
1. new ClassName()(无参构造)
2. Binding#onActivation(binding 级别激活处理器)
3. Container#onActivation(container 级别激活处理器)
4. 存入缓存
5. 注册实例到容器映射(_registerInstance)
6. 属性注入(_getInjectProperties,处理 @Inject 装饰的属性)
7. @PostConstruct(后构造方法)container.get(token) 后续调用
直接从缓存返回,不重复执行上述流程container.unbind(token)
1. Container#onDeactivation(container 级别销毁处理器)
2. Binding#onDeactivation(binding 级别销毁处理器)
3. @PreDestroy(预销毁方法)
4. 清除缓存和绑定