Rickard Oberg is popular among Java developers. He has given seminars at all main Java conferences world wide. He worked as an architect at JBoss and other popular OpenSource Java frameworks, and wrote a book on RMI. In recent years, he has become famous as an Aspect Oriented Programming (AOP) crusader. He has worked with bleeding edge AOP in a portal product that has become a great commercial success, and is currently working on Qi4j at Jayway. Rickard is a DZone MVB and is not an employee of DZone and has posted 16 posts at DZone. You can read more from them at their website. View Full User Profile

Qi4j: Fixing Dependency Injection

08.21.2008
| 6742 views |
  • submit to reddit
There was a blog post about how "Dependency Injection is Broken". The issues pointed out in the post are dealt with in Qi4j, and I'd like to briefly outline how it works.

First issue:


The problem I've always had with DI frameworks, be it Spring or Guice, is they create this nasty dependency tree. If you don't want to use GlobalApplicationContext.getBean() or Injector.getInstance() then you'll need to inject all your dependencies at the root. It annoys the crap out of me, but I suppose there's just no way around it...

This is dealt with in Qi4j by allowing objects to be instantiated without having direct access to all the dependencies needed by the object. If you have a class Foo that requires a Bar service, like this:



public class Foo
{
@Service Bar bar;
}

then you can instantiate it wherever you want by simply doing:
Foo foo = objectBuilderFactory.newObject(Foo.class);
which will instantiate Foo and provide all the dependencies it needs, without the caller having to provide them explicitly.

It is also possible to use service locators in Qi4j, like this:

public class Foo
{
@Structure ServiceFinder finder;
public void doStuff()
{
ServiceReference<Bar> barRef = finder.findService(Bar.class);
Bar bar = barRef.get();
}
}

Another issue pointed out is the ability to say "realize an object of type X, but I don't know what concrete type it should be". This is so that application code only has to be aware of the base class or interface X, which in runtime can be bound to XImpl or XMock or some other implementation. This is supported in Qi4j since all classes that are to be instantiated must be registered upfront. You can therefore register an implementation like this in the Assembler:

public void assemble(ModuleAssembly module)
{
module.addObjects(XImpl.class); // XImpl implements X interface
}

and instantiate it with:
X x = objectBuilderFactory.newObject(X.class);
Based on what you registered the appropriate implementation will be chosen. In the above case XImpl will be instantiated, and if you instead registered XMock which also implements X, then that would be instantiated. If many possibilities exist, an AmbiguousTypeException will be thrown to avoid non-deterministic behaviour.

That should take care of most of the issues pointed out in the post I think. Also note that all of the above mechanism considers visibility rules of the Layers and Modules in the Application, which can be used to further control what types are "seen" by application code in various parts of your app.

From: http://www.jroller.com/rickard/

Published at DZone with permission of Rickard Oberg, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Bob Lee replied on Thu, 2008/08/21 - 11:40am

Cross posting my comment from your blog:

Rickard, of course, you can do the exact same thing with Guice (injector.getInstance(Foo.class) instead of objectBuilderFactory.newObject(Foo.class)), but you wouldn't want to. That's just the service locator pattern which sacrifices static type checking.

The original poster's point (and mine that he referenced) was that we want language support so you can look up an object in the middle of your code and still detect missing dependencies at compile time.

Branden Makana replied on Thu, 2008/08/21 - 11:47am

Spring broken? I don't think so, but I didn't read the original post. 

 

To me though, I don't believe there is any "nasty dependency tree". For example:

 

public class ApplicationClass {

 private MyService service;

 

public void doSomething() { service.doTheThing(); }

 

 

Of course I'm ignoring getters/setters, but what's wrong with that? My application class obviously has a dependency on the service, whether it is a repository/DAO, some business method, whatever, I can't get over that dependency. Having Spring inject it doesn't seem so bad, in fact it seems pretty nice! 

Dan Turkenkopf replied on Thu, 2008/08/21 - 5:18pm in response to: Branden Makana

I think the concern of the dependency tree is that you either need to let Spring instantiate the root object of your tree (and you still have a dependency on Spring the first time that object is used), or you need to build a dependency to the ApplicationContext into all classes where you'd like injection.

Personally, I don't see the need to turn over creation of all my objects to Spring. I prefer to use dependency injection only where necessary, which normally would require a hard dependency on Spring for any objects that want to take advantage of injection. Of course you could wrap the ApplicationContext in another object to eliminate the Spring dependency, but you're still forced to call that object. Having the capability in the compiler would be very nice both in terms of removing the dependency and gaining static typing of the returned objects.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.