Spot class abstract
Lightweight service locator for dependency injection.
Spot provides a minimal yet powerful DI framework with support for:
- Singletons: Shared instance across the application
- Factories: New instance on each request
- Async Singletons: Asynchronous initialization support
- Lifecycle Hooks: Automatic cleanup via SpotDisposable interface
- Type Safety: Compile-time type checking with
R extends T - Circular Dependency Detection: Runtime detection with helpful error messages
- Testing Support: Comprehensive utilities via
SpotTestHelper - Performance: Singleton caching for faster repeated access
- Scoped Containers: Isolated dependency scopes via SpotContainer
Registration
Register dependencies during app initialization:
Spot.init((factory, single) {
// Singleton - one instance shared across app
single<ISettings, Settings>((get) => Settings());
// Factory - new instance on each request
factory<IRepository, Repository>((get) => Repository(get<Database>()));
// Singleton with dependencies
single<IApiClient, ApiClient>((get) => ApiClient(
dio: get<Dio>(),
settings: get<ISettings>(),
));
});
// Async singleton (requires async initialization)
Spot.registerAsync<Database, AppDatabase>((get) async {
final db = AppDatabase();
await db.initialize();
return db;
});
Resolution
Inject dependencies using spot or spotAsync:
// Synchronous resolution
final settings = spot<ISettings>();
final repo = Spot.spot<IRepository>();
// Asynchronous resolution
final db = await spotAsync<Database>();
final api = await Spot.spotAsync<ApiClient>();
Lifecycle Management
Services implementing SpotDisposable are automatically cleaned up:
class ApiClient implements Disposable {
final Dio dio;
ApiClient(this.dio);
@override
void dispose() {
dio.close();
}
}
// Dispose specific service
Spot.dispose<ApiClient>(); // Calls dispose() automatically
// Dispose all services
Spot.disposeAll(); // Cleanup on app shutdown
Scoped Containers
Create isolated dependency scopes for tests or feature modules:
// Global dependencies
Spot.registerSingle<ISettings, Settings>((get) => Settings());
// Create test scope
final testScope = Spot.createScope();
testScope.registerSingle<ISettings, MockSettings>((get) => MockSettings());
// Use test scope (gets mock)
final testSettings = testScope.spot<ISettings>();
// Global scope unchanged (gets real implementation)
final globalSettings = spot<ISettings>();
// Cleanup test scope
testScope.dispose();
Testing
Use SpotTestHelper for isolated test environments:
test('with mocked dependencies', () async {
await SpotTestHelper.runIsolated(() async {
SpotTestHelper.registerMock<ISettings>(MockSettings());
// Test runs with mock, original state restored after
});
});
Features
- Thread-Safe: Singleton initialization prevents race conditions
- Performance: Caching for fast repeated singleton access
- Debugging: printRegistry and isRegistered utilities
- Error Messages: Detailed errors with registered type listings
- Circular Detection: Clear error messages showing dependency cycles
- Scoped Containers: Isolated scopes via createScope
See also:
- spot for dependency resolution
- registerFactory for factory registration
- registerSingle for singleton registration
- registerAsync for async singleton registration
- SpotDisposable for lifecycle management
SpotTestHelperfor testing utilities- SpotContainer for scoped containers
- createScope for creating child scopes
Constructors
- Spot()
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Properties
Static Methods
-
createScope(
) → SpotContainer - Create a scoped container that inherits from the global Spot registry.
-
dispose<
T> ({String? name}) → void - Disposes a specific singleton instance
-
disposeAll(
) → void - Disposes all registered services
-
getRegistered<
T> ({String? name}) → SpotService< T> -
init(
void initializer(void factory< T, R extends T>(SpotGetter< void single<R> locator, {String? name}),T, R extends T>(SpotGetter< )) → voidR> locator, {String? name}) - Convenience method for registering dependencies Alternatively, you can just call Spot.registerFactory & Spot.registerSingle directly
-
isRegistered<
T> ({String? name}) → bool - Check if a type is registered without throwing an exception Useful for conditional logic and debugging
-
printRegistry(
) → void - Print all registered types with their details to the log Useful for debugging and inspecting the DI container state
-
registerAsync<
T, R extends T> (SpotAsyncGetter< R> locator, {String? name}) → void - Registers an async singleton with asynchronous initialization.
-
registerFactory<
T, R extends T> (SpotGetter< R> locator, {String? name}) → void - Registers a factory that creates a new instance on each resolution.
-
registerSingle<
T, R extends T> (SpotGetter< R> locator, {String? name}) → void - Registers a singleton that returns the same instance on each resolution.
-
spot<
T> ({String? name}) → T -
Resolves and returns an instance of type
T. -
spotAsync<
T> ({String? name}) → Future< T> -
Resolves and returns an async singleton of type
T.