Dependency Injection Container
Relevant source files
The following files were used as context for generating this wiki page:
- src/flext_core/_runtime/_dependency_bindings.py
- src/flext_core/_container_parts/flextcontainer_part_02.py
- src/flext_core/_container_parts/flextcontainer_part_04.py
- src/flext_core/_container_parts/flextcontainer_part_05.py
- src/flext_core/_protocols/_container_parts/flextprotocolscontainer_part_02.py
- src/flext_core/_models/_container_parts/flextmodelscontainer_part_02.py
- src/flext_core/_models/_container_parts/flextmodelscontainer_part_03.py
The Dependency Injection (DI) Container in FLEXT-Core provides a result-bearing API for the dispatcher-first CQRS stack. It wraps the dependency_injector library, allowing handlers and decorators to register and resolve dependencies without direct exposure to the underlying infrastructure. This isolation ensures that configuration remains separate from dispatcher logic.
Sources: src/flext_core/_container_parts/flextcontainer_part_04.py:1-9, src/flext_core/_protocols/_container_parts/flextprotocolscontainer_part_02.py:24-30
Architecture and Components
The DI system is built on a layered bridge architecture that connects declarative and dynamic modules. It manages settings, services, factories, and lifecycle-managed resources.
Layered Bridge Structure
The container uses a BridgeContainer to manage different types of dependencies through separate DynamicContainer instances for services and resources.
The diagram shows the relationship between the central BridgeContainer and its specialized module containers for configuration, services, and resources.
Sources: src/flext_core/_runtime/_dependency_bindings.py:68-76, src/flext_core/_container_parts/flextcontainer_part_02.py:101-110
Core Registration Types
The container supports three primary registration categories:
- Services: Concrete instances or values bound using
providers.Object. - Factories: Callables registered as
Singleton(cached) orFactory(non-cached) providers. - Resources: Lifecycle-managed dependencies (e.g., DB connections) registered via
providers.Resource.
Sources: src/flext_core/_runtime/_dependency_bindings.py:118-158, src/flext_core/_protocols/_container_parts/flextprotocolscontainer_part_02.py:104-120
Configuration and Implementation
Container Configuration Model
DI behavior is controlled by the ContainerConfig model, which defines how factories and services are managed.
| Field | Type | Default | Description |
|---|---|---|---|
enable_singleton | bool | True | Enables singleton pattern for factories. |
enable_factory_caching | bool | True | Enables caching of factory-created instances. |
max_services | PositiveInt | c.DEFAULT_SIZE | Max services allowed in registry. |
lazy_loading | bool | True | Enables lazy loading of services. |
enable_auto_registration | bool | False | Enables registration from decorators. |
Sources: src/flext_core/_models/_container_parts/flextmodelscontainer_part_02.py:63-125
Core Service Auto-Registration
Upon initialization, the container automatically registers essential framework services to ensure they are available for injection throughout the application.
- Config: Bound to
c.Directory.CONFIG. - Logger: A factory bound to
c.ServiceName.LOGGER. - Context: The execution context bound to
c.FIELD_CONTEXT. - Command Bus: The system dispatcher bound to
c.ServiceName.COMMAND_BUS.
Sources: src/flext_core/_container_parts/flextcontainer_part_04.py:42-59
Operational Logic
Registration and Resolution Flow
The container provides a fluent API for registration and a type-safe resolution mechanism that returns Result[T] types.
The sequence diagram illustrates the flow of binding a service and subsequently resolving it through the container's abstraction layer.
Sources: src/flext_core/_container_parts/flextcontainer_part_02.py:46-88, src/flext_core/_runtime/_dependency_bindings.py:138-146
Scoping and Isolation
Isolated scopes can be created to allow for subproject-specific overrides or context variations without affecting the global container instance.
- Cloning: Scopes clone existing services, factories, and resources.
- Overrides: Supports
ServiceRegistrationSpecto inject specific instances or settings during scope creation. - Wiring: Modules, packages, or specific classes can be wired to the container to support
@injectandProvidedecorators.
Sources: src/flext_core/_container_parts/flextcontainer_part_04.py:62-97, src/flext_core/_container_parts/flextcontainer_part_04.py:126-140
Automated Factory Registration
The shared instance of the container supports scanning the caller's module for functions decorated with @d.factory() for automatic registration.
@classmethod
def shared(
cls,
*,
settings: p.Settings | None = None,
context: p.Context | None = None,
auto_register_factories: bool = False,
) -> Self:
instance = cls()
# ... bootstrap logic ...
if auto_register_factories:
frame = inspect.currentframe()
caller_module = FlextContainer._resolve_caller_module(frame)
if caller_module is not None:
FlextContainer._auto_register_module_factories(instance, caller_module)
return instance
Sources: src/flext_core/_container_parts/flextcontainer_part_05.py:53-76
Summary
The FlextContainer serves as the central orchestration point for dependency management in FLEXT-Core. By wrapping dependency_injector with Pydantic-validated models and a result-oriented API, it provides a robust, type-safe, and isolated environment for service registration and resolution, supporting complex CQRS workflows and Clean Architecture principles.