Container API¶
::: injectq.core.container
Overview¶
The InjectQ
container is the central component of the dependency injection system. It manages service registrations, resolves dependencies, and handles scope lifecycle.
Basic Usage¶
from injectq import InjectQ, inject
# Create container
container = InjectQ()
# Register services
container.bind(UserService, UserService).singleton()
# Resolve services
user_service = container.get(UserService)
Container Methods¶
The container provides several methods for service management:
Registration Methods¶
bind()
- Register a service bindingbind_instance()
- Register a specific instancebind_factory()
- Register a factory functioninstall()
- Install a module
Resolution Methods¶
get()
- Get service instanceget_optional()
- Get optional service instancetry_get()
- Try to get service with fallback
Scope Management¶
create_scope()
- Create new scopecreate_async_scope()
- Create async scopewith_scope()
- Execute with temporary scope
Configuration Options¶
The container can be configured with various options:
container = InjectQ(
auto_wire=True, # Enable automatic wiring
validate_bindings=True, # Validate bindings on registration
thread_safe=True # Enable thread safety
)
Advanced Features¶
Custom Resolvers¶
Event Hooks¶
# Register lifecycle hooks
container.on_instance_created(lambda instance: print(f"Created: {instance}"))
container.on_scope_created(lambda scope: print(f"Scope created: {scope}"))
Validation¶
# Validate container configuration
validation_results = container.validate()
for error in validation_results.errors:
print(f"Validation error: {error}")
Thread Safety¶
The container is thread-safe by default when configured appropriately:
# Thread-safe container
container = InjectQ(thread_safe=True)
# Use from multiple threads
import threading
def worker():
service = container.get(MyService)
# Use service...
threads = [threading.Thread(target=worker) for _ in range(10)]
for thread in threads:
thread.start()
Performance Considerations¶
- Singleton services are resolved once and cached
- Scoped services are cached within their scope
- Transient services are created fresh each time
- Use
get_optional()
for services that might not be registered
Error Handling¶
The container raises specific exceptions for different error conditions:
try:
service = container.get(UnregisteredService)
except ServiceNotFoundError as e:
print(f"Service not found: {e}")
try:
container.bind(ServiceA, ServiceA)
container.bind(ServiceB, ServiceB) # Circular dependency
service = container.get(ServiceA)
except CircularDependencyError as e:
print(f"Circular dependency: {e}")