Move injection initializer to registration scope

This commit is contained in:
Mike Bierlee 2021-04-29 01:11:34 +03:00
parent 89512e0cb0
commit 8f4a64cf4c
6 changed files with 35 additions and 50 deletions

View file

@ -1,5 +1,8 @@
Poodinis Changelog
==================
**Version 8.1.0-beta.3**
* CHANGE injection initializers to be defined as a registration scope instead of via Container.register(). See initializedBy().
**Version 8.1.0-beta.2**
* FIX inheritance type template in custom instance creator (PR #29)

View file

@ -50,22 +50,28 @@ Dependency Creation Behaviour
You can control how a dependency is resolved by specifying a creation scope during registration. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available:
* Resolve a dependency using a single instance (default):
```d
dependencies.register!ExampleClass.singleInstance();
```
* Resolve a dependency with a new instance each time it is resolved:
* Resolve a dependency with a new instance each time it is resolved:
```d
dependencies.register!ExampleClass.newInstance();
```
* Resolve a dependency using a pre-existing instance
* Resolve a dependency using a pre-existing instance:
```d
auto preExistingInstance = new ExampleClass();
dependencies.register!ExampleClass.existingInstance(preExistingInstance);
```
* Resolve a dependency using a custom initializer delegate:
```d
dependencies.register!ExampleClass.initializedBy({
return new ExampleClass();
});
```
Automatic Injection
----------
The real value of any dependency injection framework comes from its ability to automatically inject dependencies. Poodinis supports automatic injection either through autowiring members annotated with the `@Autowire` UDA or through constructor injection.

View file

@ -15,7 +15,7 @@ class Doohickey
void main()
{
auto dependencies = new shared DependencyContainer();
dependencies.register!Doohickey({
dependencies.register!Doohickey.initializedBy({
writeln("Creating Doohickey via initializer delegate.");
return new Doohickey();
});

View file

@ -30,8 +30,6 @@ debug {
import std.stdio;
}
alias InjectionInitializer(T) = T delegate();
/**
* Exception thrown when errors occur while resolving a type in a dependency container.
*/
@ -149,11 +147,6 @@ synchronized class DependencyContainer {
return register!(ConcreteType, ConcreteType)(options);
}
Registration register(ConcreteType)(InjectionInitializer!ConcreteType initializer,
RegistrationOption options = RegistrationOption.none) {
return register!(ConcreteType, ConcreteType)(initializer, options);
}
/**
* Register a dependency by super type.
*
@ -201,45 +194,6 @@ synchronized class DependencyContainer {
return newRegistration;
}
/**
* TODO: Deduplicate code
*/
Registration register(SuperType, ConcreteType : SuperType)(InjectionInitializer!SuperType initializer,
RegistrationOption options = RegistrationOption.none)
if (is(ConcreteType == class)) {
TypeInfo registeredType = typeid(SuperType);
TypeInfo_Class concreteType = typeid(ConcreteType);
debug(poodinisVerbose) {
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
}
auto existingRegistration = getExistingRegistration(registeredType, concreteType);
if (existingRegistration) {
return existingRegistration;
}
InstanceFactory instanceFactory = new class InstanceFactory {
protected override Object createInstance() {
return cast(Object)initializer();
}
};
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, instanceFactory, this);
newRegistration.singleInstance();
static if (!is(SuperType == ConcreteType)) {
if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) {
auto concreteTypeRegistration = register!ConcreteType;
concreteTypeRegistration.linkTo(newRegistration);
}
}
registrations[registeredType] ~= cast(shared(Registration)) newRegistration;
return newRegistration;
}
private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) {
return ((options | persistentOptions) & option) != 0;
}

View file

@ -105,6 +105,17 @@ public Registration existingInstance(Registration registration, Object instance)
return registration;
}
/**
* Scopes registrations to create instances using the given initializer delegate.
*/
public Registration initializedBy(T : Object)(Registration registration, T delegate() initializer) {
registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.no, null, {
return cast(Object) initializer();
});
return registration;
}
public string toConcreteTypeListString(Registration[] registrations) {
auto concreteTypeListString = "";
foreach (registration ; registrations) {

View file

@ -80,6 +80,17 @@ version(unittest) {
assert(expectedInstance is actualInstance, "Resolved instance from existing instance scope is not the same as the registered instance");
}
// Test creating instance via customer initializer on resolve
unittest {
auto container = new shared DependencyContainer();
auto expectedInstance = new TestClass();
container.register!TestClass.initializedBy({
return expectedInstance;
});
auto actualInstance = container.resolve!TestClass;
assert(expectedInstance is actualInstance, "Resolved instance does not come from the custom initializer");
}
// Test autowire resolved instances
unittest {
auto container = new shared DependencyContainer();