Flow-DI
A Rust dependency injection framework inspired by C# AutoFac and Microsoft.Extensions.DependencyInjection.
中文文档 | English
Features
- Three Lifetime Management Types: Singleton, Scoped, Transient
- Keyed Service Support: Named services and key-based service resolution
- Automatic Dependency Injection: Automatic dependency injection when creating service instances
- Fluent API: Easy-to-use service registration API using builder pattern
- Circular Dependency Detection: Automatic detection and prevention of circular dependencies
- Thread Safety: Full support for multi-threaded environments
- Scope Management: Nested scopes and automatic resource cleanup
- Object Safety: Core traits are dyn-compatible for flexible usage patterns
Quick Start
Add this to your Cargo.toml:
[]
= "0.1.0"
Basic Usage
use ;
use Arc;
// Define service interface
// Implement service
Lifetime Management
Singleton
Services registered as singleton will have only one instance throughout the application lifetime:
use ;
let provider = new
.
.build;
let instance1 = provider..unwrap;
let instance2 = provider..unwrap;
// instance1 and instance2 are the same instance
assert!;
Scoped
Services registered as scoped will share the same instance within the same scope:
use ;
let provider = new
.
.build;
let mut scope = provider.create_scope.unwrap;
let service1 = scope..unwrap;
let service2 = scope..unwrap;
// service1 and service2 are the same instance within the same scope
assert!;
Transient
Services registered as transient will create a new instance for each request:
use ;
let provider = new
.
.build;
let instance1 = provider..unwrap;
let instance2 = provider..unwrap;
// Each time is a new instance
assert!;
Named Services
You can register multiple implementations of the same interface using different names:
use ;
// Register named services
let provider = new
.
.
.build;
// Resolve named services
let primary = provider..unwrap;
let secondary = provider..unwrap;
assert_eq!;
assert_eq!;
Dependency Injection
Services can depend on other services, and dependencies will be automatically injected:
use ;
use Arc;
;
let provider = new
// Register logger
.
// Register repository with logger dependency
.
// Register service with multiple dependencies
.
.build;
let mut scope = provider.create_scope.unwrap;
let user_service = scope..unwrap;
let user = user_service.get_user;
println!; // Output: User 123
Service Scopes
Service scopes provide isolation for scoped services and automatic resource cleanup:
use ;
let provider = new
.
.build;
// Create scope
let mut scope = provider.create_scope.unwrap;
// ServiceScope also implements ServiceProvider, so it can be used to resolve services
let service = scope..unwrap;
println!;
// Release scope
scope.dispose;
// Check if disposed
let is_disposed = scope.is_disposed;
assert!;
API Reference
ContainerBuilder
The ContainerBuilder provides a fluent API for registering services:
Basic Registration Methods
add_singleton<TService, TImplementation>(factory)- Register singleton serviceadd_scoped<TService, TImplementation>(factory)- Register scoped serviceadd_transient<TService, TImplementation>(factory)- Register transient serviceadd_instance<T>(instance)- Register singleton instance
Simple Registration Methods (No Dependencies)
add_singleton_simple<TService, TImplementation>(factory)- Register singleton service without dependenciesadd_scoped_simple<TService, TImplementation>(factory)- Register scoped service without dependenciesadd_transient_simple<TService, TImplementation>(factory)- Register transient service without dependencies
Dependency Injection Methods
add_singleton_with_deps<TService, TImplementation, TDep>(factory)- Register singleton with one dependencyadd_singleton_with_deps2<TService, TImplementation, TDep1, TDep2>(factory)- Register singleton with two dependencies- Similar methods for
scopedandtransient
Named Service Methods
add_named_singleton<TService, TImplementation>(name, factory)- Register named singletonadd_named_scoped<TService, TImplementation>(name, factory)- Register named scoped serviceadd_named_transient<TService, TImplementation>(name, factory)- Register named transient serviceadd_named_instance<T>(name, instance)- Register named singleton instance
ServiceProvider
The ServiceProvider provides methods for resolving services:
Core Methods (Object-Safe)
get_service_raw(&self, key: &ServiceKey)- Get raw service asArc<dyn Any>
Extension Methods (via ServiceProviderExt trait)
get_service<T>()- Get optional service of type Tget_required_service<T>()- Get required service of type T (panics if not found)get_keyed_service<T>(key)- Get optional named serviceget_required_keyed_service<T>(key)- Get required named servicecreate_scope()- Create a new service scope
ServiceScope
Service scopes provide isolated contexts for scoped services:
- Implements
ServiceProviderExttrait - Automatic resource cleanup on disposal
- Thread-safe operations
- Nested scope support
Architecture
Object Safety
Flow-DI is designed with object safety in mind:
ServiceProvidertrait is object-safe and can be used asdyn ServiceProviderServiceProviderExtprovides generic methods via extension trait pattern- Automatic implementation for all
ServiceProviderimplementors
Thread Safety
All components are thread-safe:
- Services can be resolved from multiple threads
- Scopes can be created and managed concurrently
- Singleton instances are safely shared across threads
Memory Management
- Uses
Arc<T>for service instances to enable safe sharing - Automatic cleanup of scoped services when scopes are disposed
- No memory leaks from circular dependencies (detection prevents them)
Examples
See the examples directory for complete examples:
- Basic Usage - Comprehensive example showing all features
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Inspired by AutoFac for .NET
- Inspired by Microsoft.Extensions.DependencyInjection