Tuesday, March 29, 2005
Context IoC
It also creates a whole lot of indirection, and it doesn't tackle the problem of how one creates the implementations of all those interfaces, which people rightly pointed out in the comments for the article. But then, Sony did make the point that part of his argument is that IoC/DI is a design pattern, not a framework, and, being a design pattern, it wasn't the point to provide a nice API for achieving IoC.
I, on the other hand, do want a framework that makes this idea for IoC workable. And so I set off to learn AspectJ to help me do that. Part of my goal is to make an IoC container that is invisible to the developer. You use it, and you know you use it, but it doesn't show up in your code. For instance, if I create a new object:
MyObject obj = new MyObject();Then that should be all I need to do, and (with the help of AspectJ), the new object will be injected with everything it needs to function.
One of the primary uses of such dependency injection is to ease the delivery of highly changeable configuration information to the code that uses it. And so, of course, this framework must provide a mechanism for reading/creating that config info. I suppose XML is the standard for such info, but since I dislike XML for config info, I've gone another route. I've used a simplified format for basic text information, and supplemented it with Groovy for more complex info. In other words, your new object could essentially be provided it's context by a groovy script or groovy class file, either of which can be easily modified after the system has been compiled and deployed.
Not to be confused with the idea of Context interfaces describing a class's dependencies, I realized I would need the concept of different contexts to allow multiple sets of configuration data and flexibility. I'm using a tree structure to organize such contexts, using file-path type naming (ie "root/childContext/grandChildContext") and allowing children contexts to inherit configuration information from their parents. I use AspectJ to keep track of what the context is of the current code, so that when you call new MyObject(), it will be configured with the same context as the currently executing code. If you want to change contexts, you use new MyObject(String contextName).
Ok, so what's the result of this experiment? Interestingly, my configuration information does not need to specify a list of services to be created and stored in some sort of service locator. Nor do I need to use singletons - though a Context implementation can be defined in such a way that it will end up being a shared object for all classes that declare themselves dependent on it. However, this shared behavior is hidden away in the aspect and framework code. All the developer ever writes is new ObjectIWantToUse().
At first, I did write code to handle the loading and startup of such services, but I am finding that I don't actually need it. I wasn't out to remove the use of Singletons or service locators (I'm pragmatic enough to make use of both), but I'm happy with this unexpected result. My goal was to make it easy and simple to write code that is highly configurable, and effortless to write. To remove a lot of boring code that we often have to write wherein we are essentially just passing around information to classes - instead, I wanted the information to get to those classes transparently. And by doing so, encourage greater use of dynamic config-file-type info.
On the downside, using AspectJ to intercept calls to constructors means creating objects is more costly performance-wise. Fortunately, my aspects don't intercept calls to every constructor - only those of classes that implement a ContextOriented interface. Still, the difference is drastic - being about 100x slower than normal object creation (not counting whatever code you might write to pass needed info to that new object, so it's not an entirely fair comparison). I'm hopeful, however, that this performance blip won't be too disabling, as it's fairly specific to object creation, and not a universal slowdown (in other words, I'm hoping the penalty in terms of absolute performance isn't that great).
