Synchronize DependencyContainer

The implication is that dependency containers are now always shared data. In the sense of application context, this is acceptable.
This commit is contained in:
Mike Bierlee 2015-03-28 16:36:02 +01:00
parent 8d268846ed
commit 9860624148
4 changed files with 548 additions and 548 deletions

View file

@ -79,7 +79,7 @@ private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAd
* *
* See_Also: Autowire * See_Also: Autowire
*/ */
public void autowire(Type)(DependencyContainer container, Type instance) { public void autowire(Type)(shared(DependencyContainer) container, Type instance) {
debug(poodinisVerbose) { debug(poodinisVerbose) {
printDebugAutowiredInstance(typeid(Type), &instance); printDebugAutowiredInstance(typeid(Type), &instance);
} }
@ -93,7 +93,7 @@ private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType, void*
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, candidateInstanceAddress, instanceType, instanceAddress, member)); writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, candidateInstanceAddress, instanceType, instanceAddress, member));
} }
private void autowireMember(string member, Type)(DependencyContainer container, Type instance) { private void autowireMember(string member, Type)(shared(DependencyContainer) container, Type instance) {
static if(__traits(compiles, __traits(getMember, instance, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, instance, member)))) { static if(__traits(compiles, __traits(getMember, instance, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, instance, member)))) {
foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, instance, member))) { foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, instance, member))) {
static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) { static if (__traits(isSame, autowireAttribute, Autowire) || is(autowireAttribute == Autowire!T, T)) {
@ -138,9 +138,9 @@ public void globalAutowire(Type)(Type instance) {
} }
class AutowiredRegistration(RegistrationType : Object) : Registration { class AutowiredRegistration(RegistrationType : Object) : Registration {
private DependencyContainer container; private shared(DependencyContainer) container;
public this(TypeInfo registeredType, DependencyContainer container) { public this(TypeInfo registeredType, shared(DependencyContainer) container) {
enforce(!(container is null), "Argument 'container' is null. Autowired registrations need to autowire using a container."); enforce(!(container is null), "Argument 'container' is null. Autowired registrations need to autowire using a container.");
this.container = container; this.container = container;
super(registeredType, typeid(RegistrationType)); super(registeredType, typeid(RegistrationType));

View file

@ -44,7 +44,7 @@ class ResolveException : Exception {
* In most cases you want to use a global singleton dependency container provided by getInstance() to manage all dependencies. * In most cases you want to use a global singleton dependency container provided by getInstance() to manage all dependencies.
* You can still create new instances of this class for exceptional situations. * You can still create new instances of this class for exceptional situations.
*/ */
class DependencyContainer { synchronized class DependencyContainer {
private Registration[][TypeInfo] registrations; private Registration[][TypeInfo] registrations;
private Registration[] autowireStack; private Registration[] autowireStack;
@ -111,16 +111,16 @@ class DependencyContainer {
return existingRegistration; return existingRegistration;
} }
AutowiredRegistration!ConcreteType newRegistration = new AutowiredRegistration!ConcreteType(registeredType, this); auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, this);
newRegistration.singleInstance(); newRegistration.singleInstance();
registrations[registeredType] ~= newRegistration; registrations[registeredType] ~= cast(shared(Registration)) newRegistration;
return newRegistration; return newRegistration;
} }
private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) { private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) {
auto existingCandidates = registrationType in registrations; auto existingCandidates = registrationType in registrations;
if (existingCandidates) { if (existingCandidates) {
return getRegistration(*existingCandidates, qualifierType); return getRegistration(cast(Registration[]) *existingCandidates, qualifierType);
} }
return null; return null;
@ -218,13 +218,13 @@ class DependencyContainer {
throw new ResolveException("Type not registered.", resolveType); throw new ResolveException("Type not registered.", resolveType);
} }
Registration registration = getQualifiedRegistration(resolveType, qualifierType, *candidates); Registration registration = getQualifiedRegistration(resolveType, qualifierType, cast(Registration[]) *candidates);
QualifierType instance; QualifierType instance;
if (!autowireStack.canFind(registration)) { if (!(cast(Registration[]) autowireStack).canFind(registration)) {
autowireStack ~= registration; autowireStack ~= cast(shared(Registration)) registration;
instance = cast(QualifierType) registration.getInstance(new AutowireInstantiationContext()); instance = cast(QualifierType) registration.getInstance(new AutowireInstantiationContext());
autowireStack.popBack(); autowireStack = autowireStack[0 .. $-1];
} else { } else {
auto autowireContext = new AutowireInstantiationContext(); auto autowireContext = new AutowireInstantiationContext();
autowireContext.autowireInstance = false; autowireContext.autowireInstance = false;

View file

@ -69,7 +69,7 @@ version(unittest) {
// Test autowiring concrete type to existing instance // Test autowiring concrete type to existing instance
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentB = new ComponentB(); auto componentB = new ComponentB();
container.autowire!(ComponentB)(componentB); container.autowire!(ComponentB)(componentB);
@ -78,7 +78,7 @@ version(unittest) {
// Test autowiring interface type to existing instance // Test autowiring interface type to existing instance
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
auto componentD = new ComponentD(); auto componentD = new ComponentD();
container.autowire!(ComponentD)(componentD); container.autowire!(ComponentD)(componentD);
@ -87,7 +87,7 @@ version(unittest) {
// Test autowiring will only happen once // Test autowiring will only happen once
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(InterfaceA, ComponentC).newInstance(); container.register!(InterfaceA, ComponentC).newInstance();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
container.autowire!(ComponentD)(componentD); container.autowire!(ComponentD)(componentD);
@ -99,14 +99,14 @@ version(unittest) {
// Test autowiring unregistered type // Test autowiring unregistered type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
assertThrown!(ResolveException)(container.autowire!(ComponentD)(componentD), "Autowiring unregistered type should throw ResolveException"); assertThrown!(ResolveException)(container.autowire!(ComponentD)(componentD), "Autowiring unregistered type should throw ResolveException");
} }
// Test autowiring member with non-autowire attribute does not autowire // Test autowiring member with non-autowire attribute does not autowire
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto componentE = new ComponentE(); auto componentE = new ComponentE();
container.autowire!ComponentE(componentE); container.autowire!ComponentE(componentE);
assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire"); assert(componentE.componentC is null, "Autowiring should not occur for members with attributes other than @Autowire");
@ -114,7 +114,7 @@ version(unittest) {
// Test autowire class with alias declaration // Test autowire class with alias declaration
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentDeclarationCocktail = new ComponentDeclarationCocktail(); auto componentDeclarationCocktail = new ComponentDeclarationCocktail();
@ -125,7 +125,7 @@ version(unittest) {
// Test autowire class with qualifier // Test autowire class with qualifier
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto componentX = container.resolve!(InterfaceA, ComponentX); auto componentX = container.resolve!(InterfaceA, ComponentX);
@ -138,7 +138,7 @@ version(unittest) {
// Test autowire class with multiple qualifiers // Test autowire class with multiple qualifiers
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
auto componentC = container.resolve!(InterfaceA, ComponentC); auto componentC = container.resolve!(InterfaceA, ComponentC);
@ -153,7 +153,7 @@ version(unittest) {
// Test getting instance from autowired registration will autowire instance // Test getting instance from autowired registration will autowire instance
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB), container).singleInstance(); auto registration = new AutowiredRegistration!ComponentB(typeid(ComponentB), container).singleInstance();

View file

@ -102,14 +102,14 @@ version(unittest) {
// Test register concrete type // Test register concrete type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto registration = container.register!(TestClass)(); auto registration = container.register!(TestClass)();
assert(registration.registeredType == typeid(TestClass), "Type of registered type not the same"); assert(registration.registeredType == typeid(TestClass), "Type of registered type not the same");
} }
// Test resolve registered type // Test resolve registered type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestClass)(); container.register!(TestClass)();
TestClass actualInstance = container.resolve!(TestClass)(); TestClass actualInstance = container.resolve!(TestClass)();
assert(actualInstance !is null, "Resolved type is null"); assert(actualInstance !is null, "Resolved type is null");
@ -118,7 +118,7 @@ version(unittest) {
// Test register interface // Test register interface
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestInterface, TestClass)(); container.register!(TestInterface, TestClass)();
TestInterface actualInstance = container.resolve!(TestInterface)(); TestInterface actualInstance = container.resolve!(TestInterface)();
assert(actualInstance !is null, "Resolved type is null"); assert(actualInstance !is null, "Resolved type is null");
@ -127,13 +127,13 @@ version(unittest) {
// Test resolve non-registered type // Test resolve non-registered type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving non-registered type does not fail"); assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving non-registered type does not fail");
} }
// Test clear registrations // Test clear registrations
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestClass)(); container.register!(TestClass)();
container.clearAllRegistrations(); container.clearAllRegistrations();
assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving cleared type does not fail"); assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving cleared type does not fail");
@ -148,7 +148,7 @@ version(unittest) {
// Test resolve single instance for type // Test resolve single instance for type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestClass)().singleInstance(); container.register!(TestClass)().singleInstance();
auto instance1 = container.resolve!(TestClass); auto instance1 = container.resolve!(TestClass);
auto instance2 = container.resolve!(TestClass); auto instance2 = container.resolve!(TestClass);
@ -157,7 +157,7 @@ version(unittest) {
// Test resolve new instance for type // Test resolve new instance for type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestClass)().newInstance(); container.register!(TestClass)().newInstance();
auto instance1 = container.resolve!(TestClass); auto instance1 = container.resolve!(TestClass);
auto instance2 = container.resolve!(TestClass); auto instance2 = container.resolve!(TestClass);
@ -166,7 +166,7 @@ version(unittest) {
// Test resolve existing instance for type // Test resolve existing instance for type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto expectedInstance = new TestClass(); auto expectedInstance = new TestClass();
container.register!(TestClass)().existingInstance(expectedInstance); container.register!(TestClass)().existingInstance(expectedInstance);
auto actualInstance = container.resolve!(TestClass); auto actualInstance = container.resolve!(TestClass);
@ -175,7 +175,7 @@ version(unittest) {
// Test autowire resolved instances // Test autowire resolved instances
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!AutowiredClass; container.register!AutowiredClass;
container.register!ComponentClass; container.register!ComponentClass;
auto componentInstance = container.resolve!ComponentClass; auto componentInstance = container.resolve!ComponentClass;
@ -185,7 +185,7 @@ version(unittest) {
// Test circular autowiring // Test circular autowiring
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!ComponentMouse; container.register!ComponentMouse;
container.register!ComponentCat; container.register!ComponentCat;
auto mouse = container.resolve!ComponentMouse; auto mouse = container.resolve!ComponentMouse;
@ -195,7 +195,7 @@ version(unittest) {
// Test remove registration // Test remove registration
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!TestClass; container.register!TestClass;
container.removeRegistration!TestClass; container.removeRegistration!TestClass;
assertThrown!ResolveException(container.resolve!TestClass); assertThrown!ResolveException(container.resolve!TestClass);
@ -203,7 +203,7 @@ version(unittest) {
// Test autowiring does not autowire member where instance is non-null // Test autowiring does not autowire member where instance is non-null
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto existingA = new AutowiredClass(); auto existingA = new AutowiredClass();
auto existingB = new ComponentClass(); auto existingB = new ComponentClass();
existingB.autowiredClass = existingA; existingB.autowiredClass = existingA;
@ -218,7 +218,7 @@ version(unittest) {
// Test autowiring circular dependency by third-degree // Test autowiring circular dependency by third-degree
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!Eenie; container.register!Eenie;
container.register!Meenie; container.register!Meenie;
container.register!Moe; container.register!Moe;
@ -230,7 +230,7 @@ version(unittest) {
// Test autowiring deep circular dependencies // Test autowiring deep circular dependencies
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!Ittie; container.register!Ittie;
container.register!Bittie; container.register!Bittie;
container.register!Banana; container.register!Banana;
@ -242,7 +242,7 @@ version(unittest) {
// Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time // Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(Ittie).newInstance(); container.register!(Ittie).newInstance();
container.register!(Bittie).newInstance(); container.register!(Bittie).newInstance();
container.register!(Banana).newInstance(); container.register!(Banana).newInstance();
@ -254,7 +254,7 @@ version(unittest) {
// Test autowiring type registered by interface // Test autowiring type registered by interface
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!Banana; container.register!Banana;
container.register!Bittie; container.register!Bittie;
container.register!(SuperInterface, SuperImplementation); container.register!(SuperInterface, SuperImplementation);
@ -266,7 +266,7 @@ version(unittest) {
// Test reusing a container after clearing all registrations // Test reusing a container after clearing all registrations
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!Banana; container.register!Banana;
container.clearAllRegistrations(); container.clearAllRegistrations();
try { try {
@ -280,14 +280,14 @@ version(unittest) {
// Test register multiple concrete classess to same interface type // Test register multiple concrete classess to same interface type
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
} }
// Test removing all registrations for type with multiple registrations. // Test removing all registrations for type with multiple registrations.
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
container.removeRegistration!Color; container.removeRegistration!Color;
@ -295,7 +295,7 @@ version(unittest) {
// Test registering same registration again // Test registering same registration again
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto firstRegistration = container.register!(Color, Blue); auto firstRegistration = container.register!(Color, Blue);
auto secondRegistration = container.register!(Color, Blue); auto secondRegistration = container.register!(Color, Blue);
@ -304,7 +304,7 @@ version(unittest) {
// Test resolve registration with multiple qualifiers // Test resolve registration with multiple qualifiers
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
try { try {
@ -317,7 +317,7 @@ version(unittest) {
// Test resolve registration with multiple qualifiers using a qualifier // Test resolve registration with multiple qualifiers using a qualifier
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
auto blueInstance = container.resolve!(Color, Blue); auto blueInstance = container.resolve!(Color, Blue);
@ -330,7 +330,7 @@ version(unittest) {
// Test autowire of unqualified member typed by interface. // Test autowire of unqualified member typed by interface.
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!Spiders; container.register!Spiders;
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
@ -341,7 +341,7 @@ version(unittest) {
// Register existing registration // Register existing registration
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto firstRegistration = container.register!TestClass; auto firstRegistration = container.register!TestClass;
auto secondRegistration = container.register!TestClass; auto secondRegistration = container.register!TestClass;
@ -351,7 +351,7 @@ version(unittest) {
// Register existing registration by supertype // Register existing registration by supertype
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
auto firstRegistration = container.register!(TestInterface, TestClass); auto firstRegistration = container.register!(TestInterface, TestClass);
auto secondRegistration = container.register!(TestInterface, TestClass); auto secondRegistration = container.register!(TestInterface, TestClass);
@ -361,7 +361,7 @@ version(unittest) {
// Resolve dependency depending on itself // Resolve dependency depending on itself
unittest { unittest {
auto container = new DependencyContainer(); shared(DependencyContainer) container = new DependencyContainer();
container.register!Recursive; container.register!Recursive;
auto instance = container.resolve!Recursive; auto instance = container.resolve!Recursive;