Skip to content

生命周期

简介

本库的生命周期包括两个阶段:激活(Activation)销毁(Deactivation)

  • 激活阶段:在 container.get(token) 首次解析服务时触发,涉及 Binding#onActivationContainer#onActivation@PostConstruct 三个钩子。
  • 销毁阶段:在调用 container.unbind(token) / container.unbindAll() / container.destroy() 时触发,涉及 Container#onDeactivationBinding#onDeactivation@PreDestroy 三个钩子。

激活顺序

本库激活顺序

Binding#onActivation → Container#onActivation → @PostConstruct

inversify 激活顺序

@PostConstruct → Binding#onActivation → Container#onActivation

设计原因

本库将 @PostConstruct 放在最后执行,是因为 @PostConstruct 方法中通常需要访问通过 @Inject 装饰的属性。

属性注入(_getInjectProperties)发生在 activation 阶段之后。如果 @PostConstruct 在 activation 之前执行,此时注入的属性还未就绪,会导致 @PostConstruct 中访问注入属性时得到 undefined

已知限制

activation handler(Binding#onActivationContainer#onActivation)中不能访问注入的属性,因为此时属性注入还未完成。

销毁顺序

本库与 inversify 的销毁顺序相同:

Container#onDeactivation → Binding#onDeactivation → @PreDestroy

触发时机

  • container.unbind(token):解绑指定 token,触发该 token 对应服务的销毁流程
  • container.unbindAll():解绑当前容器中所有 token
  • container.destroy():递归销毁所有子容器,并解绑当前容器中所有 token

@PostConstruct 继承行为

沿继承链向上查找,执行第一个找到的 @PostConstruct 方法,找到即停止。

场景一:A 继承 B,A 和 B 都有 @PostConstruct

只执行 A 的 @PostConstruct,B 的不执行。

ts
@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

ts
@Injectable()
class B {
  @PostConstruct()
  init() {
    console.log('B init'); // 会执行
  }
}

class A extends B {
  // A 没有 @PostConstruct
}

场景三:A 继承 B 继承 C,A 和 B 都没有 @PostConstruct

执行 C 的 @PostConstruct

ts
@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

也就是说如果当前类还有其他类型的依赖,比如有些依赖是通过 toConstantValuetoDynamicValue 绑定的服务,@PostConstruct 是不会等待它们完成。 就算toDynamicValue本身是返回了一个promise。

ts
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 参数。

ts
// ✅ 宿主类 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. 清除缓存和绑定