Quick start
This page builds a two-service program in about five minutes. You'll register services with an injector and then ask it for one, letting it build the dependencies for you.
1. Write some services
Every service needs two things:
- a factory, which says this is how to build it, and
- a provider, which says an injector makes this service available.
The recommended convention is to keep both on the service itself, as static Factory and DefaultProvider members. Your services stay plain Dart classes that don't extend or implement anything.
class Logger {
// How to build a Logger.
static final Factory = InjectableFactory.withoutDependencies<Logger>(
() => Logger(),
);
// How to make a Logger available in an injector.
static final DefaultProvider = Provider(Logger);
void log(String message) => print('[log] $message');
}
class GreetingService {
GreetingService(this._logger);
static final Factory = InjectableFactory.withDependencies<GreetingService>(
DependencyDataBuilder.list([Logger]),
(deps) => GreetingService(deps.get<Logger>()),
);
static final DefaultProvider = Provider(GreetingService);
final Logger _logger;
String greet(String name) {
_logger.log('greeting $name');
return 'Hello, $name!';
}
}DependencyDataBuilder.list([Logger]) tells the injector that GreetingService needs a Logger. The injector resolves it before calling the factory, and deps.get<Logger>() hands it over.
Lint note
Factory and DefaultProvider are capitalized on purpose so they read like part of the type. The lints package flags that with non_constant_identifier_names, so turn that rule off in analysis_options.yaml:
analyzer:
errors:
non_constant_identifier_names: ignore2. Create an injector
Registration now reads as a list of services:
// 1. Say which services this injector makes available.
final injector = Injector([
Logger.DefaultProvider,
GreetingService.DefaultProvider,
]);
// 2. Register how to build each one.
injector.registerFactories([
Logger.Factory,
GreetingService.Factory,
]);3. Ask for a service
getService returns a Future, because any service in the chain may be asynchronous.
// 3. Ask for a service. Its dependencies are built first.
final greeter = await injector.getService<GreetingService>();
final message = greeter.greet('Dart');
print(message); // Hello, Dart!The Logger is built first, then the GreetingService. Both are cached in the injector, so the next getService call returns the same instances.
The whole program
Show full source
import 'package:complete_dependency_injector/complete_dependency_injector.dart';
class Logger {
// How to build a Logger.
static final Factory = InjectableFactory.withoutDependencies<Logger>(
() => Logger(),
);
// How to make a Logger available in an injector.
static final DefaultProvider = Provider(Logger);
void log(String message) => print('[log] $message');
}
class GreetingService {
GreetingService(this._logger);
static final Factory = InjectableFactory.withDependencies<GreetingService>(
DependencyDataBuilder.list([Logger]),
(deps) => GreetingService(deps.get<Logger>()),
);
static final DefaultProvider = Provider(GreetingService);
final Logger _logger;
String greet(String name) {
_logger.log('greeting $name');
return 'Hello, $name!';
}
}
Future<String> runQuickStart() async {
// 1. Say which services this injector makes available.
final injector = Injector([
Logger.DefaultProvider,
GreetingService.DefaultProvider,
]);
// 2. Register how to build each one.
injector.registerFactories([
Logger.Factory,
GreetingService.Factory,
]);
// 3. Ask for a service. Its dependencies are built first.
final greeter = await injector.getService<GreetingService>();
final message = greeter.greet('Dart');
print(message); // Hello, Dart!
await injector.dispose();
return message;
}
void main() => runQuickStart();Where to go next
- Core concepts explains providers, factories, tokens and scopes in more depth.
- The API reference lists every class and method.