Service Providers
A powerful dependency injection and service registration system for organizing and bootstrapping your Khadem application.
Dependency InjectionService RegistrationBoot LifecycleModular Architecture
System Overview
Service Provider Architecture
Service providers are the foundation of Khadem's dependency injection system. They provide a clean, organized way to register services, configure dependencies, and execute initialization logic.
Core Components
- ServiceProviderManager - Main orchestrator
- ServiceProviderRegistry - Provider registration
- ServiceProviderBootloader - Boot lifecycle
- ServiceProviderValidator - Validation system
Key Features
- Deferred loading support
- Async boot lifecycle
- Type-safe provider management
- Validation and error handling
Provider Lifecycle
1
Registration
Provider is registered with the container. Services and dependencies are bound.
2
Boot
After all providers are registered, boot() method is called for initialization.
3
Ready
Application is fully initialized and all services are available.
Quick Start
Basic Setup
1. Create a Service Provider
dart
import 'package:khadem/khadem.dart';
class DatabaseServiceProvider extends ServiceProvider {
@override
void register(ContainerInterface container) {
// Register database connection
container.singleton(DatabaseConnection.new);
// Register repository classes
container.singleton<UserRepository>(UserRepository.new);
container.singleton<PostRepository>(PostRepository.new);
}
@override
Future<void> boot(ContainerInterface container) async {
// Initialize database connection
final db = container.make<DatabaseConnection>();
await db.connect();
print('โ
Database service initialized');
}
}
2. Register the Provider
dart
import 'package:khadem/khadem.dart';
void main() async {
// Initialize Khadem
await Khadem.initialize();
// Create service provider manager
final container = Khadem.container;
final providerManager = ServiceProviderManager(container);
// Register providers
providerManager.register(DatabaseServiceProvider());
providerManager.register(CacheServiceProvider());
providerManager.register(AuthServiceProvider());
// Boot all providers
await providerManager.bootAll();
print('๐ Application started with all services');
}
Provider Types
Regular Providers
dart
import 'package:khadem/khadem.dart';
class CacheServiceProvider extends ServiceProvider {
@override
void register(ContainerInterface container) {
// Register cache implementation
container.singleton<CacheInterface>(RedisCache.new);
// Register cache manager
container.singleton(CacheManager.new);
}
@override
Future<void> boot(ContainerInterface container) async {
final cache = container.make<CacheInterface>();
await cache.connect();
print('โ
Cache service initialized');
}
// This is a regular provider (loaded immediately)
@override
bool get isDeferred => false;
}
Loaded immediately when the application starts. Use for core services and essential dependencies.
Deferred Providers
dart
import 'package:khadem/khadem.dart';
class EmailServiceProvider extends ServiceProvider {
@override
void register(ContainerInterface container) {
// Register email service
container.singleton<EmailService>(SmtpEmailService.new);
// Register mailer
container.singleton(Mailer.new);
}
@override
Future<void> boot(ContainerInterface container) async {
final emailService = container.make<EmailService>();
await emailService.verifyConnection();
print('โ
Email service initialized');
}
// This is a deferred provider (loaded only when needed)
@override
bool get isDeferred => true;
}
Loaded only when their services are actually needed. Improves application startup performance.
Advanced Usage
Complex Service Registration
dart
import 'package:khadem/khadem.dart';
class ApiServiceProvider extends ServiceProvider {
@override
void register(ContainerInterface container) {
// Register HTTP client with configuration
container.singleton<HttpClient>(() {
final config = container.make<Config>();
return HttpClient(
baseUrl: config.get('api.base_url'),
timeout: Duration(seconds: config.get('api.timeout', 30)),
headers: {
'Authorization': 'Bearer ${config.get('api.token')}',
'Accept': 'application/json',
},
);
});
// Register API services
container.singleton<UserApiService>(UserApiService.new);
container.singleton<PostApiService>(PostApiService.new);
container.singleton<NotificationApiService>(NotificationApiService.new);
// Register API client facade
container.singleton<ApiClient>(ApiClient.new);
}
@override
Future<void> boot(ContainerInterface container) async {
final httpClient = container.make<HttpClient>();
final apiClient = container.make<ApiClient>();
// Test API connectivity
try {
await httpClient.get('/health');
print('โ
API connection established');
} catch (e) {
print('โ API connection failed: $e');
rethrow;
}
// Initialize API services
await apiClient.initialize();
}
}
Boot-time Initialization
dart
import 'package:khadem/khadem.dart';
class MonitoringServiceProvider extends ServiceProvider {
@override
void register(ContainerInterface container) {
// Register monitoring services
container.singleton<MetricsCollector>(MetricsCollector.new);
container.singleton<HealthChecker>(HealthChecker.new);
container.singleton<AlertManager>(AlertManager.new);
}
@override
Future<void> boot(ContainerInterface container) async {
final metrics = container.make<MetricsCollector>();
final healthChecker = container.make<HealthChecker>();
final alertManager = container.make<AlertManager>();
// Start background monitoring tasks
metrics.startCollecting();
healthChecker.startPeriodicChecks();
// Set up alert handlers
alertManager.registerHandler('database', (alert) {
print('๐จ Database alert: ${alert.message}');
// Send notification, log to external service, etc.
});
alertManager.registerHandler('memory', (alert) {
print('๐จ Memory alert: ${alert.message}');
// Trigger garbage collection, scale resources, etc.
});
// Start alert manager
await alertManager.start();
print('โ
Monitoring system initialized');
}
}
Provider Management
dart
import 'package:khadem/khadem.dart';
class ProviderManager {
final ServiceProviderManager _manager;
ProviderManager(ContainerInterface container)
: _manager = ServiceProviderManager(container);
// Register core providers
void registerCoreProviders() {
_manager.registerAll([
DatabaseServiceProvider(),
CacheServiceProvider(),
AuthServiceProvider(),
RoutingServiceProvider(),
]);
}
// Register optional providers
void registerOptionalProviders() {
_manager.registerAll([
EmailServiceProvider(),
QueueServiceProvider(),
MonitoringServiceProvider(),
]);
}
// Boot providers in phases
Future<void> bootApplication() async {
// Phase 1: Boot core services first
await _manager.bootNonDeferred();
// Phase 2: Boot deferred services when needed
// This can be called later when services are actually needed
// await _manager.bootDeferred();
print('โ
Application booted successfully');
}
// Get provider statistics
void printProviderStats() {
print('\n๐ Provider Statistics:');
print('Total providers: ${_manager.providerCount}');
print('Booted: ${_manager.isBooted ? 'Yes' : 'No'}');
print('Deferred providers: ${_manager.deferredProviders.length}');
print('Non-deferred providers: ${_manager.nonDeferredProviders.length}');
// Validate providers
final validationErrors = _manager.validateProviders();
if (validationErrors.isEmpty) {
print('โ
All providers are valid');
} else {
print('โ Validation errors:');
for (final error in validationErrors) {
print(' - $error');
}
}
}
// Get providers by type
List<DatabaseServiceProvider> getDatabaseProviders() {
return _manager.getProvidersByType<DatabaseServiceProvider>();
}
// Clean up
void reset() {
_manager.clear();
print('๐งน All providers cleared');
}
}
// Usage
final providerManager = ProviderManager(container);
providerManager.registerCoreProviders();
await providerManager.bootApplication();
providerManager.printProviderStats();
Management Operations
Registration
register(provider)
- Register single providerregisterAll(providers)
- Register multiple providersisRegistered(provider)
- Check if registered
Boot Control
bootAll()
- Boot all providersbootNonDeferred()
- Boot non-deferred onlybootDeferred()
- Boot deferred only
Validation & Error Handling
dart
import 'package:khadem/khadem.dart';
class ProviderValidator {
final ServiceProviderManager _manager;
ProviderValidator(this._manager);
// Validate all providers before booting
bool validateAllProviders() {
final errors = _manager.validateProviders();
if (errors.isEmpty) {
print('โ
All providers passed validation');
return true;
} else {
print('โ Provider validation failed:');
for (final error in errors) {
print(' - $error');
}
return false;
}
}
// Custom validation logic
List<String> customValidation() {
final errors = <String>[];
final providers = _manager.allProviders;
// Check for required providers
final hasDatabase = providers.any((p) => p is DatabaseServiceProvider);
if (!hasDatabase) {
errors.add('DatabaseServiceProvider is required but not registered');
}
// Check for circular dependencies (simplified example)
final dependencyGraph = _buildDependencyGraph(providers);
final cycles = _detectCycles(dependencyGraph);
if (cycles.isNotEmpty) {
errors.add('Circular dependencies detected: $cycles');
}
// Check provider naming conventions
for (final provider in providers) {
if (!provider.runtimeType.toString().endsWith('ServiceProvider')) {
errors.add('${provider.runtimeType} does not follow naming convention');
}
}
return errors;
}
Map<String, List<String>> _buildDependencyGraph(List<ServiceProvider> providers) {
// Simplified dependency analysis
return {};
}
List<String> _detectCycles(Map<String, List<String>> graph) {
// Simplified cycle detection
return [];
}
// Validate provider boot order
List<String> validateBootOrder() {
final errors = <String>[];
final deferred = _manager.deferredProviders;
final nonDeferred = _manager.nonDeferredProviders;
// Ensure critical services are not deferred
final criticalServices = ['DatabaseServiceProvider', 'AuthServiceProvider'];
for (final service in criticalServices) {
final isDeferred = deferred.any((p) => p.runtimeType.toString() == service);
if (isDeferred) {
errors.add('$service should not be deferred (critical service)');
}
}
return errors;
}
}
// Usage
final validator = ProviderValidator(manager);
if (validator.validateAllProviders()) {
final customErrors = validator.customValidation();
final bootErrors = validator.validateBootOrder();
if (customErrors.isEmpty && bootErrors.isEmpty) {
await manager.bootAll();
} else {
print('โ Custom validation failed:');
[...customErrors, ...bootErrors].forEach(print);
}
}
Validation Features
- Automatic provider validation before registration
- Detection of duplicate providers
- Dependency validation (extensible)
- Detailed error reporting with specific issues
- Graceful handling of validation failures
Best Practices
โ Do's
- Use deferred providers for non-essential services to improve startup performance
- Keep provider logic focused and single-responsibility
- Use meaningful names for your providers and services
- Implement proper error handling in boot() methods
- Document dependencies and requirements in provider comments
- Group related services in the same provider when logical
- Use the container for dependency injection instead of manual instantiation
- Test your providers thoroughly, especially boot logic
โ Don'ts
- Don't perform heavy operations in register() - use boot() instead
- Don't create circular dependencies between providers
- Don't skip validation - always validate your providers
- Don't use providers for one-off utilities - use regular classes
- Don't make all providers deferred - core services need immediate loading
- Don't ignore boot errors - handle them appropriately
- Don't register the same provider multiple times
- Don't put business logic in providers - keep them focused on DI
API Reference
ServiceProvider Interface
dart
abstract class ServiceProvider {
/// Called when the provider is registered in the container.
/// Use this method to bind services and dependencies.
void register(ContainerInterface container);
/// Called after all providers are registered.
/// Use this method for initialization logic that requires other services.
Future<void> boot(ContainerInterface container) async {}
/// If true, the provider is deferred and only loaded when needed.
/// Deferred providers improve startup performance.
bool get isDeferred => false;
}
// Example implementation
class MyServiceProvider extends ServiceProvider {
@override
void register(ContainerInterface container) {
// Register services here
container.singleton(MyService.new);
}
@override
Future<void> boot(ContainerInterface container) async {
// Initialization logic here
final service = container.make<MyService>();
await service.initialize();
}
@override
bool get isDeferred => true; // Optional: make it deferred
}
ServiceProviderManager
dart
class ServiceProviderManager {
// Constructor
ServiceProviderManager(ContainerInterface container)
// Registration methods
void register(ServiceProvider provider) // Register single provider
void registerAll(List<ServiceProvider> providers) // Register multiple providers
// Boot methods
Future<void> bootAll() // Boot all providers
Future<void> bootNonDeferred() // Boot only non-deferred providers
Future<void> bootDeferred() // Boot only deferred providers
// Query methods
List<ServiceProvider> get allProviders // Get all providers
bool get isBooted // Check if all providers are booted
List<String> validateProviders() // Validate all providers
bool get areAllValid // Check if all providers are valid
List<T> getProvidersByType<T>() // Get providers by type
List<ServiceProvider> get deferredProviders // Get deferred providers
List<ServiceProvider> get nonDeferredProviders // Get non-deferred providers
int get providerCount // Get total provider count
// Utility methods
void clear() // Clear all providers and reset state
}
ServiceProviderRegistry
dart
class ServiceProviderRegistry {
// Constructor
ServiceProviderRegistry(ContainerInterface container)
// Properties
List<ServiceProvider> get providers // Get all registered providers (unmodifiable)
// Registration methods
void register(ServiceProvider provider) // Register single provider
void registerAll(List<ServiceProvider> providers) // Register multiple providers
// Query methods
bool isRegistered(ServiceProvider provider) // Check if provider is registered
List<T> getProvidersByType<T>() // Get providers by type
List<ServiceProvider> getDeferredProviders() // Get deferred providers
List<ServiceProvider> getNonDeferredProviders() // Get non-deferred providers
int get count // Get total provider count
// Utility methods
void clear() // Clear all registered providers
}
ServiceProviderBootloader
dart
class ServiceProviderBootloader {
// Constructor
ServiceProviderBootloader(ContainerInterface container)
// Properties
bool get isBooted // Check if all providers have been booted
// Boot methods
Future<void> bootProvider(ServiceProvider provider) // Boot single provider
Future<void> bootProviders(List<ServiceProvider> providers) // Boot multiple providers
Future<void> bootAll(List<ServiceProvider> providers) // Boot all providers
Future<void> bootNonDeferred(List<ServiceProvider> providers) // Boot non-deferred only
Future<void> bootDeferred(List<ServiceProvider> providers) // Boot deferred only
// Utility methods
void reset() // Reset boot state
}