mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Fix autowiring deep circular dependencies
This commit is contained in:
parent
b88745130a
commit
b66b9d5def
|
@ -123,12 +123,11 @@ assert(instance.dependency !is null);
|
||||||
If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired.
|
If an interface is to be autowired, you must register a concrete class by interface. Any class registered by concrete type can only be injected when a dependency on a concrete type is autowired.
|
||||||
|
|
||||||
###Circular dependencies
|
###Circular dependencies
|
||||||
Poodinis can autowire circular dependencies to a certain degree. See known issues for current limitations on this. For now you might want to consider if your design really needs circular dependencies.
|
Poodinis can autowire circular dependencies when they are registered with singleInstance or existingInstance registration scopes. See Known issues for the limitations on newInstance scopes.
|
||||||
|
|
||||||
Known issues
|
Known issues
|
||||||
------------
|
------------
|
||||||
* Circular dependencies down the dependency tree still fails if the dependencies don't refer to the type being resolved initially.
|
* Due to preventive measures of recursion issues in circular dependencies, registrations which are supposed to yield new instances will not autowire classes for which a circular dependency is detected. A new instance will be resolved but the instance's members will not be autowired.
|
||||||
* Due to preventive measures of recursion issues in circular dependencies, registrations which are supposed to yield new instances will not autowire classes for which a recursive resolve is detected.
|
|
||||||
|
|
||||||
Future Work
|
Future Work
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -9,6 +9,7 @@ module poodinis.container;
|
||||||
|
|
||||||
import std.string;
|
import std.string;
|
||||||
import std.array;
|
import std.array;
|
||||||
|
import std.algorithm;
|
||||||
|
|
||||||
public import poodinis.registration;
|
public import poodinis.registration;
|
||||||
public import poodinis.autowire;
|
public import poodinis.autowire;
|
||||||
|
@ -31,7 +32,7 @@ class Container {
|
||||||
|
|
||||||
private Registration[TypeInfo] registrations;
|
private Registration[TypeInfo] registrations;
|
||||||
|
|
||||||
private Registration* registrationBeingResolved;
|
private Registration*[] autowireStack;
|
||||||
|
|
||||||
public Registration register(ConcreteType)() {
|
public Registration register(ConcreteType)() {
|
||||||
return register!(ConcreteType, ConcreteType)();
|
return register!(ConcreteType, ConcreteType)();
|
||||||
|
@ -54,18 +55,12 @@ class Container {
|
||||||
throw new ResolveException("Type not registered.", resolveType);
|
throw new ResolveException("Type not registered.", resolveType);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto initialResolve = false;
|
|
||||||
if (registrationBeingResolved is null) {
|
|
||||||
registrationBeingResolved = registration;
|
|
||||||
initialResolve = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegistrationType instance = cast(RegistrationType) registration.getInstance();
|
RegistrationType instance = cast(RegistrationType) registration.getInstance();
|
||||||
if (initialResolve || registrationBeingResolved !is registration) {
|
|
||||||
|
if (!autowireStack.canFind(registration)) {
|
||||||
|
autowireStack ~= registration;
|
||||||
this.autowire!(RegistrationType)(instance);
|
this.autowire!(RegistrationType)(instance);
|
||||||
}
|
autowireStack.popBack();
|
||||||
if (initialResolve) {
|
|
||||||
registrationBeingResolved = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
|
|
|
@ -58,6 +58,21 @@ version(unittest) {
|
||||||
public Eenie eenie;
|
public Eenie eenie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Ittie {
|
||||||
|
@Autowire
|
||||||
|
public Bittie bittie;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bittie {
|
||||||
|
@Autowire
|
||||||
|
public Banana banana;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Banana {
|
||||||
|
@Autowire
|
||||||
|
public Bittie bittie;
|
||||||
|
}
|
||||||
|
|
||||||
// Test register concrete type
|
// Test register concrete type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new Container();
|
auto container = new Container();
|
||||||
|
@ -185,4 +200,28 @@ version(unittest) {
|
||||||
|
|
||||||
assert(eenie.meenie.moe.eenie is eenie, "Autowiring third-degree circular dependency failed");
|
assert(eenie.meenie.moe.eenie is eenie, "Autowiring third-degree circular dependency failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test autowiring deep circular dependencies
|
||||||
|
unittest {
|
||||||
|
auto container = new Container();
|
||||||
|
container.register!Ittie;
|
||||||
|
container.register!Bittie;
|
||||||
|
container.register!Banana;
|
||||||
|
|
||||||
|
auto ittie = container.resolve!Ittie;
|
||||||
|
|
||||||
|
assert(ittie.bittie is ittie.bittie.banana.bittie, "Autowiring deep dependencies failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time
|
||||||
|
unittest {
|
||||||
|
auto container = new Container();
|
||||||
|
container.register!(Ittie).newInstance();
|
||||||
|
container.register!(Bittie).newInstance();
|
||||||
|
container.register!(Banana).newInstance();
|
||||||
|
|
||||||
|
auto ittie = container.resolve!Ittie;
|
||||||
|
|
||||||
|
assert(ittie.bittie.banana.bittie.banana is null, "Autowiring deep dependencies with newInstance scope autowired a reoccuring type.");
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue