Dependency Injection – Part 2

Picture of a syringe

Last week I introduced the concept of dependency injection. This week we look at how we implement DI in code.

Implementing Dependency Injection

Dependency injection has three common implementation mechanisms:

Constructor Injection

Constructor Injection provides the class’s dependencies in its constructor(s). We declare a constructor or a set of constructors taking the dependencies as arguments. The DI container passes these dependencies to the class when it instantiates it. Constructor injection is usually used for mandatory (usually immutable) dependencies. Constructor injection is 100% portable between containers.

Setter Injection

Setter Injection provides the class’s dependencies using JavaBean-style setter methods. The DI container uses these setters to inject the dependencies. Setter injection is usually used for optional dependencies. This lets us create reconfigurable objects which can be changed later at runtime by calling the setters. Setter injection is 100% portable between containers.

Field Injection

Field injection is done using annotations on fields. The container uses the Reflection API to access the fields directly. The dependency values are injected directly into the fields of the class when the container instantiates it. Field injection is very easy to use, but is usually container-specific and not portable.

Code Examples

Last week I used the example of an InvoiceProcessor that has a dependency on a DatabaseManager. How does a container wire the dependency? We need to write the class in a way that supports constructor, setter and/or field injection.

Constructor Injection

public class InvoiceProcessor {
// dependency
private DatabaseManager dbManager;
// constructor
public InvoiceProcessor (DatabaseManager dbManager) {
// set the DatabaseManager after data validation code
this.dbManager = dbManager;
}
// other code ...
}

Setter Injection

public class InvoiceProcessor {
// dependency
private DatabaseManager dbManager;
// setter
public setDatabaseManager (DatabaseManager dbManager) {
// set the DatabaseManager after data validation code
this.dbManager = dbManager;
}
// other code ...
}

Field Injection

public class InvoiceProcessor {
// The container injects a DatabaseManager instance
// directly into the field.

@Inject (from JSR 330)
private DatabaseManager dbManager;
// other code ...
}

We could replace the @Inject annotation with any of the following annotations, depending on the DI container we’re using:

  • @Resource (from JSR 250)
  • @Named (from JSR 299)
  • @Autowired (Spring specific)

A JEE application server only supports the annotations that are part of the JEE specification (JSRs 250, 299, 330). Spring has its own annotations and supports all the JEE annotations as well.

Wrapping Up

In all three examples above, the DI container creates an instance of DatabaseManager (or one of its subclasses). It then passes this instance to the InvoiceProcessor at runtime. The InvoiceProcessor doesn’t know or care how the DatabaseManager was created. All it knows is that it has a properly initialised DatabaseManager object to use.

I haven’t shown any container code – that’s too specific for this post. The DI container can create an InvoiceProcessor instance based on instructions in a deployment descriptor, an XML file, or some other mechanism.

The important point is that we must write our classes in a way that will allow the container to inject the dependency.

Using constructor/setter injection, our classes are always decoupled from the DI container. If we decide to use field injection, we limit ourselves to a specific container.

Don’t forget to sign up to get our weekly Java tips.

Leave a Comment

Your email address will not be published. Required fields are marked *