Understanding Dependency Injection – Part 3 Contexts

So far this series has covered simple IoC dependency injection as well as bean initialization with @PostConstruct and constructor injection.

In this part we will introduce container managed contextual scopes to Voodoo DI.

A scope defines the life-cycle of a bean, allowing state to be preserved and or shared across multiple interactions. DI frameworks offer a fast variety of build-in and add-on scopes, such as @RequestScoped, @SessionScoped, @ApplicationScoped, etc…

So far Voodoo DI simply maps interfaces, supertypes and the target type directly to the concrete implementations.


For the container to manage contextual instances, the concrete implementation has to be wrapped into a contextual type.

ContextualType.class V3

The actual life-cycle management is then performed in the context specific ContextualType implementation.

In the simplest case, similar to Spring’s prototype and CDI dependent scope, Voodoo default “Puppet” scope will return a new instance every time.

PuppetContextualType.class V3

Instead of directly mapping the types to their concrete implementations, the concrete implementations have to be wrapped into the PuppetContextualType.

VoodooDI.class V3

Voodoo DI now obtains the ContextualType from the types map. The actual instantiation and life-cycle management of the targeted instance is now performed by the ContextualType implementation.

Singleton

Introducing Singleton Scope to Voodoo DI is a simple matter of implementing a singleton ContextualType.

SingletonContextualType.class V4

JSR-330 provides a standardized @Singleton annotation with which types can be marked to be managed by the singleton context.

During initialization all identified types are checked for @Singleton annotation, if present the type will be wrapped into a SingletonContextualType instead of the default PuppetContextualType.

Voodoo.class V4

Custom Scopes

So far basic context have been introduced to Voodoo DI, however these are implemented in a rather static non-extensible fashion (if(context) {...} else {...}).

To allow for custom contexts to be added we will have to enable Voodoo DI to discover available contexts on the classpath.

For this all available contexts have to extend Context.

So far we have relied on Voodoo DI TypeScanner, as stated previously this was solely implemented to proof that its possible. From here on Voodoo DI will utilize on Ron Mamo reflections library for type scanning.

To start with, Reflections scans the entire classpath, just as was the case with the TypeScanner. With reflections.getSubTypesOf(Context.class) we then discover all available contexts.

ContextManager.class V5

Each discovered context is constructed(5) and initializes all its contextual types(6).

ContextManager.class V5

The contextual types from the initialized contexts are merged(7) and as before mapped(9) to their respective type, supertypes and interfaces.

If we wanted to create a context that returns a random contextual instance (a.k.a. Pooled) to Voodoo DI we simply have to define an context annotation to mark the targeted beans.

Implement the Context, defining the annotation and implementing the contextual instance factory method.

Last but not least we will implement the contextual logic in by implementing the RandomContextualType.

Using the new random context is a simple matter of annotating the targeted bean with @Random.

In this post we covered one of the most useful features of DI frameworks, managing contextual instances. In the next post of this series we will have a look at interceptors.

Acknowledgements

I would like to thank Björn Sonntag and Robert Meyer for reviewing my posts.

2 thoughts on “Understanding Dependency Injection – Part 3 Contexts”

Leave a Reply

Your email address will not be published. Required fields are marked *