views:

274

answers:

9

I've been reading about Spring and although it's claimed to be a less complex alternative to EJB, I'm having a hard time wrapping my head around it. Is there a more minimal way of achieving Dependency Injection than adopting the Spring approach?

+3  A: 

Google Guice is a very minimalist DI framework.

Michael Borgwardt
+6  A: 

Why not just do it without a framework ?

Ask what your class depends on, and then inject those objects via (say) the constructor.

Some hints:

  1. does your class rely on a singleton ? Inject that object instead (probably as a factory)
  2. does your object rely on other concrete classes ? If so, inject those, but reference them via interfaces, so you an substitute different implementations

e.g. simply create a class with a constructor thus:

public TradeSaver(final ITradeValidator validator, final ITradeDatabase db);

(where both parameters are interfaces) and you can then inject the core components that your TradeSaver depends on (validation and database saving), with the option of providing different implementations for testing, different deployments etc.

Brian Agnew
"with the option of providing different implementations for testing, different deployments etc" -> what do you mean by that?
Chuck
You may provide a mocked version for testing. For deployment you may want to provide different implementations of ITradeDatabase for different dbs etc.
Brian Agnew
The problem is that this kind of thing gets very nasty very quickly, because you're passing stuff down the call stack like crazy and methods higher up need dozens of parameters one way or another. By the time you've encapsulated all that, you've written your own (probably inefficient, probably badly designed) DI framework.
Michael Borgwardt
It's still interesting to do for learning purpose. For example I'm ashamed to admit that when the DI craze started hitting the Java world, many years ago, I couldn't understand why it was useful (there were way less info on it than today)... So I wrote my own DI-framework and once I got it, I threw away my (badly designed) wheel.
Webinator
@Michael - I'm merely suggesting writing constructors and injection yourself, rather than use a framework. I don't see how a framework mitigates the scenario you've outlined.
Brian Agnew
@Brian: DI frameworks typically provide a central static factory that provides instances with all dependencies appropriately injected. That removes the need for the calling code to pass them as constructor parameters and thus answers the question where *that* code gets them from.
Michael Borgwardt
@Michael: I think you misunderstand DI. Object construction and the object call graph are completely decoupled in DI. The caller never has to worry about the dependencies of the callee. A DI container merely replaces a bunch of wiring code at your application entry point.
Wim Coenen
@Michael: If you're passing lots of arguments up/down the stack, you're doing it wrong.
kyoryu
@Wim: that's for the simple case where your code lives entirely within a container and all dependencies are wired at startup. If you're not writing a container-based app or your code needs to create new objects with dependencies, then you need a factory. Spring has the various BeanFactory implementations for that, and more lightweight DI frameworks like Guice use it exclusively.
Michael Borgwardt
@kyoryu: my point exactly. Brian's suggestions forces you to do it wrong unless your app is very small and simple.
Michael Borgwardt
I'm not suggesting that you have to do anything in a dogmatic fashion. You choose what's appropriate. If you want to go further and implement factories then go ahead. At that stage you're probably not injecting, though. Pragmatism (as I always preach) is the key.
Brian Agnew
And I'm not saying that your answer is wrong (it does describe the most basic form of DI), just that its applicability is very limited.
Michael Borgwardt
@Michael: I'm disagreeing with you, actually. The typical way to avoid calling down the stack is to use factories rather than the 'new' operator. If your logic flow is dealing with dependencies, there's a problem.
kyoryu
@kyoryu: ah, I think now I see where we misunderstand each other. You assume that the constructor arguments in Brian's code are injected by a factory rather than the code that uses them. But then the factory becomes an important part of the concept, so it needs to be mentioned (which it's not). And you're also already halfway towards writing your own DI framework.
Michael Borgwardt
@Michael: Yes, but only for instances where classes need to be created dynamically at runtime. In many cases, parts of the object graph are relatively static, and so can either be an aggregate object, or built by a single builder.
kyoryu
Why write yourself what others have already done? There is most likely a LOT of little devils in the details.
Thorbjørn Ravn Andersen
+2  A: 

Another option that hasn't been mentionned yet is Yan. I've used it in the past and it was very lightweight and minimalist. Here's a link with a one page introduction as to what (and how) it does:

http://yan.codehaus.org/

Webinator
+2  A: 

As far as DI and IoC goes, it probably doesn't get any more minimal than picocontainer.

I prefer Tapestry, but Google Guice is pretty similar and more widely adopted, so that might be a better choice since it will be easier to find tutorials etc.

Martin
A: 
  1. read the spring xml bean config file
  2. write it in plain java.
irreputable
+2  A: 

I highly recommend that you just try Spring. It is a bit more complicated than Guice in the initial stages, however, the wrappers for other APIs and included utilities (LDAPTemplate, JDBCTemplate, HibernateTemplate, Validators, etc) are well worth the cost of admission.

Having said that, if you are dead-set against trying Spring, Guice or Seam offer nice alternatives.

jsight
+1  A: 

In essence, dependency injection is just a way of structuring your code for reusability of components. It doesn't require the use of a container. It just means that you move any use of the "new" operator for your components to the start of your applicaiton. For example, your application entry point could look like this:

IZooDataRepository repository = new SqlZooDataRepository(somehost, someparam);
IMonkeyManager monkeyManager = new MonkeyManager(repository);
IZebraManager zebraManager = new ZebraManager(repository);
ZooProgram program = new ZooProgram(monkeyManager, zebraManager);

program.run();

This phase is known as the "object graph construction". It is where you wire objects which only know their collaborators as interfaces to specific implementations of those interfaces.

This start-up wiring can get quite long and complicated if you have hundreds of classes in practice. That's why DI containers were invented: they replace the object graph construction code in some way, e.g. like this:

Container container = new Container(someconfigurationparameters);
ZooProgram program = (ZooProgram) container.Create(ZooProgram.class);
program.run();

The configuration of the object graph produced by a container is typically done through XML files, attributes on classes, or bindings defined with code.

Wim Coenen
A: 

PicoContainer is the easiest way to get a started with DI:

suppose we got

public class A implements IA {

  public A(IB dependency){
    ...
  }
}

public class B implements IB {

}

then

pico = new DefaultPicoContainer();   
pico.addComponent(A.class);   
pico.addComponent(B.class);   

IA a = pico.getComponent(IA.class); // a is an instance of A with an instance of B passed to the constructor
Christopher Oezbek
A: 

I would strongly recommend you look into a JSR-330 implementation, as these hopefully should be the future standard. There is one in JEE6 but that may be overkill for you. I believe the Caucho CanDI can run in stand-alone too.

http://www.caucho.com/projects/candi/

Thorbjørn Ravn Andersen