Контроль времени жизни
В InferDI есть три вида времени жизни:
| Вид | Создание | Кеш | Очистка |
|---|---|---|---|
singleton | один раз на контейнер-владелец | контейнер-владелец | да |
scoped | один раз на дочерний scope | дочерний scope | да |
transient | при каждом resolve | никогда | нет |
При strict: true попытка получить scoped-ключ из root выбрасывает Scoped "key" cannot be resolved from the root container. Use createScope(). Получайте scoped-сервисы из дочернего контейнера, который вернул createScope().
Правило жизненного цикла
Singleton не может напрямую зависеть от scoped или transient сервиса. Singleton создаётся один раз и разделяется между всеми запросами, поэтому если он захватит scoped-значение - контекст текущего запроса, пользователя или транзакцию - состояние одного запроса незаметно протечёт во все остальные. InferDI делает такую связь невыразимой в системе типов, а не оставляет её на code review.
new Container()
.registerClass('request', RequestContext, [], 'scoped')
.registerClass('users', UserService, ['request'], 'singleton')Такую регистрацию отклонит TypeScript. В strict mode та же форма будет отклонена runtime-защитой, если каст обойдёт систему типов.
Строгий режим
strict: true включен по умолчанию. Он ловит:
- прямой resolve scoped-ключа из root-контейнера
- нарушения singleton-to-scoped и singleton-to-transient через касты
- утечки из фабрик, которые захватили внешний контейнер
- синхронные singleton-циклы
- синхронные transient-циклы
- неправильное использование динамических ключей, обходящее статическую проверку
const root = new Container({ strict: true })Быстрый режим
Используйте strict: false только после того, как тесты доказывают форму графа:
const root = new Container({ strict: false })Быстрый режим убирает runtime-учёт циклов и времени жизни из пути resolve. Scope читает неизменяемый root registry напрямую, не проходя цепочку родителей, а delegated singleton зеркалируется в cache scope. Strict scope при каждом локальном промахе проходит точную цепочку родителей, поэтому мутации остаются видимыми без сохранённых метаданных lookup. Дедупликация owned-инстансов выполняется во время disposal в обоих режимах. Контракт на уровне типов не меняется, но Fast Mode не защищает от нечестных кастов, захваченных внешних контейнеров и циклов. Он также отключает запрет на resolve scoped-ключей из root, поэтому код приложения не должен обращаться к ним через root-контейнер.
Рекомендуемый процесс: разрабатывать и тестировать в strict mode, регистрировать каждый runtime-ключ один раз в одной линейной fluent-цепочке и завершить регистрацию до первого resolve или создания scope. Переключайте только проверенные неизменяемые production-графы и закрывайте дочерние scope раньше предков.
