ActiveInject. Fast and Lightweight Dependency Injection Library
We'll overview the core features of ActiveInject: creating AbstractModules, working with scopes, creating named bindings, singleton\non-singleton instances.
Join the DZone community and get the full member experience.Join For Free
What is ActiveInject?
ActiveInject is a lightning-fast and powerful dependency injection library. It has a lot of tools and features to offer: support for nested scopes, singletons and transient bindings, modules, multi-threaded, and single-threaded injectors.
At the same time, it’s thoroughly optimized with all the dependencies graph preprocessing performed at startup time. According to the benchmarks, in some scenarios, ActiveInject is 5.5 times faster than Guice and hundreds of times faster than Spring DI. You can check the benchmark sources here.
ActiveInject is an independent technology of ActiveJ platform. It has no third-party dependencies on its own and can be used as a stand-alone DI library.
Let’s try the library out and bake some virtual cookies using ActiveInject. A cookie requires the following ingredients:
Butter. These ingredients form a
Pastry which can be baked into a
Cookie. Assume each of these entities has a POJO. Let’s start with a basic example:
Here we’ve created an
cookbook that contains all the required bindings, or “recipes”, for the ingredients. Call
Injector.getInstance method to get an instance of the
How does it work from the inside?
Injector provides all the required dependencies for the component recursively traversing the dependencies graph in a postorder way. So it first created
Flour, the next was
Pastry, and finally a
But what if you need some special cookie recipes for different people? For example, if you need a sugar-free
Cookie in addition to a regular one. In this case, you can use
The usage of the
@Named annotation is pretty self-illustrative. After annotating bindings you can call either
injector.getInstance(Key.ofName(Cookie.class, "normal")) or
injector.getInstance(Key.ofName(Cookie.class, "zerosugar")) and get different instances of the
One of the important ActiveInject features is that all the created instances are singleton by default. If you call
injector.getInstance(Cookie.class) several times, each time you’ll get the very same instance from the cache. You can easily check it with the following code:
This is a useful optimization, but what if we need non-singleton cookies? In this case, you can use scopes.
Scope creates “local singletons” which live as long as the scope itself. ActiveInject scopes are a bit different from other DI libraries. The internal structure of the
Injector is a prefix tree and the prefix is a scope. If you create an
Injector that is set to a particular scope, it means that
Injector enters this scope. This can be done several times so that there are multiple injectors in a single scope.
Let’s create scope for our cookies. The identifiers of the tree are annotations. So you can simply create your custom scope annotations:
Next, instantiate your scope:
@OrderScope annotation to the instances that are needed as non-singletons (
Butter) in the following way:
Now each time we need a new instance of
Injector will create a subinjector to enter the order scope and create a new instance of
Cookie, while the
Kitchen will always stay singleton in the root scope.
One more interesting ActiveInject feature is that it is fully compatible with another ActiveJ library named ActiveSpecializer.
ActiveSpecializer is a unique technology that relies on a ground-breaking concept of using runtime information about instances of the classes. ActiveSpecializer rewrites your code directly in runtime, using runtime information that is contained in the instances of your classes. To be more precise, it transforms all class fields into static class fields, de-virtualizes all the virtual methods calls, and replaces them with static method calls. ActiveSpecializer shows its best with AST-like structures, so it is very efficient with ActiveInject. According to the benchmarks, ActiveSpecializer can speed up your code to up to 7 times in some use cases.
To apply ActiveSpecializer to your
Injector simply call
Injector.useSpecializer method before
ActiveInject goes far beyond these basic examples and is capable of fine-tuning to match all your needs. You can find more examples on the official ActiveInject website.
Since ActiveInject is a part of ActiveJ, it is perfectly compatible with all the platform’s components: HTTP servers and servlets, RPC implementation, bytecode manipulation tools, abstractions for efficient management of distributed file storage, and others.
Published at DZone with permission of Valeria Listratova. See the original article here.
Opinions expressed by DZone contributors are their own.