Spring 2.5: Dependency Injection That Doesn't Hurt

Dependency injection - DI -  is a great thing. Really. The hability to tweak implementations without touching your code is awesome and the DI frameworks, like spring, saves you a lot of coding. No more service locators stuff.

But, and there is always a but, you’re left with a bunch of XML configuration. And I hate it. Not that XML files are bad… the thing is that everything nowadays has its own set of XML configurarion files. And Spring is not different.



Let’s take a look at a simple example on how dependency injection is handled in Spring.

Imagine you have a domain object called Invoice that, among other things, is somewhat defined like this:
[java]
public class Invoice {
//normal attributes and getters/setters

public void sendByEmailTo(String address) {
//code to send invoice by e-mail
}
}
[/java]

You have a method to send a certain Invoice through e-mail, probably to some customer. This method would basically do some processing, maybe formatting strings, and then, ideally, delegate the send e-mail task to someone else. Probably a infrastructure service or something similar, that I will call EmailService. This object knows how to do the low level stuff like connecting to the SMTP server and so on. So we need this object, we depend on it.  To express this dependency, the Invoice code would change to this:

[java]
public class Invoice {
//normal attributes and getters/setters
private EmailService emailService;
public void setEmailService(EmailService service) {
emailService = service;
}

public void sendByEmailTo(String address) {
//code to send invoice by e-mail
}
}
[/java]

This way the Invoice class is prepared to be injected with its only dependency using Spring. Now, what you would have to do is to declaratively express this dependency to the Spring container, so it can settle things for you. This is done through its XML configuration file, often called applicationContext. Below is the snippet of the file relevant to this example:

[xml]


 




[/xml]And that’s it. Upon initialization Spring will use this XML file to discover that the Invoice object depends on the EMailService object and inject it using the setter method we created before.

The problem is: If we have 50 domain objects that depends on 10 service objects that depends on anything else, we would end up in a XML forrest with at least 60 bean definitions.
Of course you can break this creating smaller XML files, but they are still XML files with bean definitions. Well, with Spring 2.5 we have a better option: We can use annotations!
In this new release, Spring use its own set of annotations to resolve object dependencies without XML. Let’s see how this thing works.

Our previous Invoice object would change to this:
[java]
public class Invoice {
//normal attributes and getters/setters
@AutoWired
@Qualifier(“myEmailService”)
private EmailService emailService;
public void setEmailService(EmailService service) {
emailService = service;
}

public void sendByEmailTo(String address) {
//code to send invoice by e-mail
}
}
[/java]

Let’s explain this change. The @AutoWired annotation tells spring that it should automatically wire dependencies based on its type, in our case, EmailService. But we take it a step further and choose which object to inject based not only on its type, but based on its name, with the @Qualifier annotation.

 Hmm… you may be asking now - But where did we say the object name is myEmailService?

 Okay, the other leg of the magic is on the @Component annotation:

[java]
@Component(“myEmailService”)
public class EmailService {
//methods
}
[/java]

With this annotation, you register a new component available for injection within the Spring container. This way, you don’t need to put neither the Invoice objects, nor its dependencies in the xml files. Pretty, huh?

But one question remains: How the hell spring knows about this annotated classes?
This is the one-million question and the answer is simple. You do need an XML file, but just to tell spring where to look for annotated classes, this way:

[xml]


[/xml]

The first clause sets the container to support annotation based configuration. The second one, component-scan, defines the base package where Spring should look for anotated classes within your project. That’s how it will be able to discover who needs who and who is a eligible component for injection.

You are really left with a small, tiny, piece of XML. Much more clean, elegant and much less XML to type.

Comments