Dependency Injection without Reflection
Joa Ebert has written a Dependency Injection framework as part of his funk-as3 library.
Basically his API is orientated on Google Guice and does not use reflection, which is great, because reflection is pretty expensive regarding performance.
And Performance matters. We reduced the start-up time of our application from 8 seconds to 3 seconds just by removing Spring Actionscript and using a pure factory-based DI which does not use reflection and has no performance overhead. The code was also better to manage then the XML based solution of Spring Actionscript. Other frameworks which are more in the Guice-style would be nice to use but have the same negative impact on performance, so it was a No-Go for us. The drawback of our factory-based solution compared to Guice-style frameworks was, that it was not so easy and nice to use and more boilerplate code has to be written.
When stumbling over Joa Eberts DI framework I first wanted to use it directly as 3rd party library but I got some problems with the compiled swc. So I started to build my own small DI framework based on previous ideas in this direction and refined with some of his ideas and a similar API style. Unfortunately I cannot share the code but I can give the basic ideas.
So let’s get started:
First you need to setup the Locator. It’s a one-liner and is done like this:
[code lang="actionscript3"]myLocator = Locator.getLocator("myScope", myContext); [/code]
The explanation for this will follow later.
Further you have a Context Class (the Module in Guice) where you define the bindings of what you want to get injected for a special Interface, Class or named annotation.
Additionally you define if the object should be only created once (asSingleton) or every time newly.
[code lang="actionscript3"]// Interface to Class bind(ITestInterface).to(TestImpl).asSingleton(); // String annotation to Class bind("myList").to(ArrayCollection); // Interface to instance bind(IResourceManager).to(resourceManager).asSingleton(); [/code]
To support also some special classes which are outside of your control (3rd party) you can use a Provider to get an instance created in a custom fashion in the Providers getObject() method.
[code lang="actionscript3"]// String annotation to Provider bind("myServcice").to(RemoteObjectServiceProvider).asSingleton(); [/code]
When you want to inject these objects somewhere in your Classes, just write inject(bindingKey) to obtain the instance defined in the Context.
But when not using reflection we are facing some problems.
Without reflection you don’t have information at run-time about the constructor arguments. This is a problem when creating the classes. One solution to prevent this problem is to use only constructors without arguments.
Instead of the classical way like here:
[code lang="actionscript3"]public function TestClass(testInstance:ITestInterface) { this.testInstance = testInstance; }[/code]
We assign the mandatory members directly in the constructors body with the inject call.
[code lang="actionscript3"]public function TestClass() { testInstance = inject(ITestInterface); } [/code]
Another solution would be to register the Class with it’s parameters annotations explicitly to the framework, so the information what needs to be injected when creating this Class is available.
Something like this (you can use a static function call as it is specific to the class, so it could be located directly above the Constructor):
[code lang="actionscript3"]registerClass(TestClass).withParams([ ITestInterface, "myList" ]); public function TestClass(testInstance:ITestInterface, myList:ArrayCollection) { this.testInstance = testInstance; this.myList = myList; }[/code]
This would have the drawback that you need to maintain changes in the parameters in 2 places, and additional code needs to be written.
My preferred solution without constructor arguments has the drawback that the mandatory parameters are not visible in the signature of the constructor.
So both has some small penalties, but the good thing is it has zero overhead performance-wise and it is as easy to use like the classic Guice style injection.
Of course you can use the injection in properties or methods as well. But i prefer the constructor injection for all mandatory dependencies, so it’s more clear what a class needs initially.
So how does it work:
Technically it is not real injection but more like the Locator pattern.
You have a Dictionary where you define the mappings of keys (Interface, Class or named annotation as String) to instances, Classes or Providers.
What happened when calling the inject() method inside the Locator?
It looks up for the value stored for the given key.
That can be:
- An instance, so return it.
- A Class, so create an instance of this Class and return it.
- A Provider. Create an instance of the Provider and call the getObject() method to get back an instance which is created in a customized way and return this instance.
The optional asSingleton() call is handling the behavior if the object is cached or not.
So why not use the Locator pattern?
When using the Locator pattern you need the instance of the Locator. You can pass the Locator in the constructor to not rely on a static dependency inside your class.
That would be fine, but there is a more elegant way.
You can use a package level function (native Flash Functions like getTimer() or trace() are using this technique), so you can call directly the function without reference to the Locator. Inside the function it forwards the call to the package level property which got assigned the reference to the Locator from the setup. The “dependency” is only the package in which these 2 files are defined. If you follow a clear architectural structure this results in the positive side effect, that your Locator is used only in the correct scope and protects from cross-scope misuse.
Note that the file name must be the same like the Function or Property names (inject.as, myInjector.as) and only one Function/Property is allowed.
Here are code examples like these 2 files could look like:
[code lang="actionscript3"]package org.yourDomain.yourProject { public function inject(bindingKey:Object):Object { return myInjector.inject(bindingKey); } }[/code]
[code lang="actionscript3"]package org.yourDomain.yourProject { import org.yourDomain.Injector; public var myInjector:Injector; }[/code]
The myLocator property gets the concrete Locator instance assigned at the setup.
[code lang="actionscript3"]myLocator = Locator.getLocator("myScope", myContext);[/code]
Scopes:
When having a single project you probably don’t need to use different scopes, but this becomes important for larger projects. As different projects are normally using different root packages, the projects root package would be a perfect candidate for the scope key.
When you add the package level property and function file into these packages, you have in every project the access to the right scope of your Locator (need to import them where used).
The Locator implementation is pretty straight forward.
It does the management of the scopes as well as the mapping and handling (creation) of the instances when the inject() is called. I used the fluent interface style but you could implement the Binding also with a plain function and parameters.
Some final discussion:
So you may ask that fetching dependencies is not the same like injecting them, and classes should get the dependencies from outside instead of fetching them from inside.
Yes that is basically true.
But why it is better to get it injected?
Because normally to fetch something you need a reference to the container from where you get it. In classical ServiceLocator patterns it is mostly a Singleton.
[code lang="actionscript3"]ServiceLocator.getInstance().getObject("myObject");[/code]
Better would be to inject the ServiceLocator in the constructor, so the provider of your dependencies is free configurable and you don’t need to change your class if you want to use a different implementation of the provider.
It is not about getting or fetching, it it about to keep the class clean from static dependencies.
With the solution using package level functions it is less code needed to be written and has the benefit to implement a scope mechanism which can serve as protection.
Maybe it depends on the architecture and structure of the project if this approach makes sense. Another solution would be to pass the scope to the Constructor of the Class and lookup for the Locator inside the constructor with the scope key. Or simply pass the already resolved Locator instance typed as Interface to the Constructor.
So using it a bit different, the good old ServiceLocator mimics the fancy Guice-style Dependency Injection without really hurting, but saving a lot of performance.
Comments (9)
Category: Actionscript,Flash,Flex,Performance
Comment by Hannes
Made Tuesday, 31 of January , 2012 at 22:45
Cool approach!
would it be possible to port it to Javascript?
Thanks
Hannes
Comment by Manfred Karrer
Made Tuesday, 31 of January , 2012 at 23:03
I am absolute no Javascript guy, and my AS1 days are long gone… I think the basic idea should be portable but in a bit different style. You need to define somewhere a Class definition (prototype in js, right?) which will be used to create dynamically an object out of it. I guess that should be possible. You can pass the injector over the constructor and ask for the objects you want to get injected. That is basically a look up in an hash-map followed by a dynamic creation of an object from the class/prototype definition. The package level function/property style will probably not be possible in js.
Comment by Hannes
Made Monday, 6 of February , 2012 at 13:00
I really like your approach, in particular that you are not using reflection.
But you started from the same question like other Frameworks (ie. Robotlegs) did: “How can we handle this huge amount of dependencies in an easy, code less, way?”
Thats the wrong question.
The right one is: “How can we reduce dependencies?”
Do you have an answer for that?
Comment by Manfred Karrer
Made Tuesday, 7 of February , 2012 at 13:05
No answer for that ;-). Yes I agree, reducing unnecessary dependencies is a good point. But you always will have some dependencies which needs to be managed, even if it is a low number.
Comment by Hannes
Made Tuesday, 7 of February , 2012 at 13:07
I think we need to find an answer for that!
Comment by Manfred Karrer
Made Tuesday, 7 of February , 2012 at 13:16
But code reuse in OOP brings dependencies in. And I think dependencies which are clear defined, are not a problem.
Comment by Hannes
Made Tuesday, 7 of February , 2012 at 13:18
less dependencies, more freedom and independence!
Pingback by Dependency Injection with code generation | nucleo.io
Made Friday, 30 of March , 2012 at 20:28
[…] Unfortunately there is no solution out there beside a project from Joa Ebert, who is using a different approach. I wrote about this in another blog entry. […]
Pingback by Dependency Injection with code generation | .:. blog.screenshot.at .:. Flash, Flex, RIA .:.
Made Monday, 16 of February , 2015 at 17:21
[…] Unfortunately there is no solution out there beside a project from Joa Ebert, who is using a different approach. I wrote about this in another blog entry. […]
Sorry, the comment form is closed at this time.