Dependency Injection refers to the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency.
Inversion of control, is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to the traditional architecture of software libraries.
For me those two terms have always described the way a framework is wiring your components at startup, no matter if that framework is called PicoContainer, Spring or Guice. It is in control of creating and passing the dependencies to your application, in order for it to run.
The wiring is usually done in the main method of your application or a ContextListener, in case of a webapp. If you are using Spring, for example, you would create an ApplicationContext, which bootstraps the dependencies of your entry point class:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
Service s = ctx.getBean("calculationService"); // wires all dependencies
s.start(); // everything is setup already
One of the reasons I like Spring and this particular DI / IoC notion, is that there is no need for creating instance with the new operator. After the initial setup your application is good to go and your dependencies are fully initialized. In webapps this usually works like a charm. In desktop applications, especially if you are using an application framework, it's a little different.
I'm working on a Eclipse RCP desktop app at the moment and combining it with my notion of DI / IoC turns out to be virtually impossible. One of the reasons is OSGi, the underlying technology of the Eclipse RCP. The nature of OSGi is highly dynamic. Bundles and thus dependencies can come and go at runtime. That means the traditional wiring approach isn't suitable. In my project, we are using Spring Dynamic Modules, which somewhat combines the static nature of wiring with OSGi's dynamic capabilities.
The probably most important reason why my understanding of DI /IoC isn't working in our application, is the fact that we are trying to mix Spring's life-cycle and IoC capabilities with that of Eclipse. The Rich Application Platform has its own notion of wiring and if you base your application on it, you must comply with that. The way Eclipse wires its dependencies is similar to that of Spring, but not compatible after all.
Instead of having dependencies injected by Spring in a inversion of control way, we are basically left with the good old Service Locator.
The fundamental choice is between Service Locator and Dependency Injection...is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.
Although there are solutions, bridging the gap between Eclipse and Spring, there's nothing supported "officially". That was the reason for us to go the Service Locator route, although to me it doesn't feel right. There are pros and cons when it comes to the Service Locator pattern. One of the most compelling arguments against it, is the hard reference to the locator instance in your code. It is a necessary evil in order to get a hold of your dependencies. This pain point was kind of mitigated for me, when I read that Netbeans is using it in their code base to lookup dependencies as well.
The solution we came up with, is a static ApplicationContext instance in the Activator class of each OSGi bundle. It serves as a location to grab the dependencies needed in the contained environment of a bundle. The ApplicationContext is configured using the usual Spring XML-configuration, together with Spring Dynamic Modules. An alternative approach, that we considered as well, is to use the OSGi API to locate your services. It limits the dependencies to Spring, since you don't need a reference to the ApplicationContext. If you are planning to replace Spring with anything else, you might consider taking that approach.
Although this works very well, it doesn't fit my understanding of DI and IoC. I want my dependencies to be injected, wherever I need them. I don't want to ask for them myself. Martin Fowler mentions in his article, that using the black magic of IoC, in contrast to the ServiceLocator pattern, makes your code harder to understand and debug. I can think of situation where it's harder to debug your code, but I cannot imagine how your code would be harder to grasp. I think, if you clearly state the dependencies of your class, it is easier to comprehend and to test. The fact that Spring does some magic and injects the dependencies for you, doesn't harm understandability at all.
Trying to get the best of both worlds - Eclipse RCP and Spring - probably means to compromise about doing DI using a Service Locator instead of doing DI with IoC. But isn't everything we do in software development a compromise?
5 comments:
Hi David you may want to take a look at
http://www.it-agile.de/fileadmin/docs/JFS-2005-Dependency-Injection.pdf (in german)
Actually an extension point might be used to do dependency injection, because it can be used to inject an arbitrary number of plugins that extend it. For DI the number of plugins that implement the given extension point is equal to 1.
Hi David,
You should checkout the SpringSource dm Server: http://www.springsource.com/products/suite/dmserver
It's basically the Eclipse/Equinox OSGi server with a bunch of extra bundles that support Spring development on top of OSGi.
Hi Markus,
thanks for the pointer.
Actually an extension point might be used to do dependency injection, because it can be used to inject an arbitrary number of plugins that extend it. For DI the number of plugins that implement the given extension point is equal to 1.
Sounds like Martin Lippert's approach that I linked in the blog: http://martinlippert.blogspot.com/2008/05/dependency-injection-for-extensions.html.
It looks quite promising and I hope it'll be incorporated in Spring DM.
Instead of putting a config in every module, we use a single static class in one module and is exposed by importing the package. Otherwise I would have to hit every module to change the implementation. On the client we pretty much only inject services. I do use it for other "singletons" because I have apps that i want to function in RCP and RAP.
This was great to read, thank you
Post a Comment