Dependency Injection vs. Service Locator

Again, while reading through the Spring documentation, I came across this article of Martin Fowler.
I’ll try to give a summary of his article and my opinions about it.

Introduction

Every professional software engineer should know what dependency injection or inversion of control is about, but i’ll try to explain it for those who don’t.
I’ll use quite the same examples as Martin did in his article, which I’ll try to update a little. You can find a link to the source code at the bottom of this blog post (Maven is required to build the source).

Imagine you have to display a list of movies directed by a specified director.
I have an interface and a concrete implementation for finding movies.

public interface MovieFinder {
    public List<Movie> findAllMovies();
}
public class MovieFinderDummy implements MovieFinder {
    public List<Movie> findAllMovies() {
        List<Movie> movies = new ArrayList<Movie>();

        movies.add(new Movie("Gangs of New York", "Martin Scorsese"));
        movies.add(new Movie("E.T.: The Extra-Terrestrial", "Steven Spielberg"));
        movies.add(new Movie("The Aviator", "Martin Scorsese"));
        movies.add(new Movie("Indiana Jones and the Temple of Doom", "Steven Spielberg"));
        movies.add(new Movie("Jurassic Park", "Steven Spielberg"));

        return movies;
    }
}

To list the movies with a specified director, the following code is used:

public class MovieLister {
    private MovieFinder movieFinder;

    public Movie[] listMoviesDirectedBy(String director) {
        List<Movie> allMovies = movieFinder.findAllMovies();
        for (Iterator<Movie> iterator = allMovies.iterator(); iterator.hasNext();) {
            Movie movie = iterator.next();
            if (!movie.getDirector().equals(director)) {
                iterator.remove();
            }
        }

        return allMovies.toArray(new Movie[allMovies.size()]);
    }
}

Especially the MovieFinder at line 02 is of importance here.
You need to have a way to provide the concrete class that will be used for this MovieFinder instance.

Basic solution

What you can do is specify the MovieFinder‘s concrete class in the MovieLister‘s default constructor, like this:

public class MovieLister {
    private MovieFinder movieFinder;

    public MovieLister() {
        movieFinder = new MovieFinderDummy();
    }

    ...

You’ll see. The code works. But we’ll soon be in trouble when sharing this service with other developers who are going to use it for their own projects.
If another developer also wants to use the MovieLister, but wants to get his movies from a text file, a database or XML, he’ll have to change the code of the default constructor.
Of course in our case, he can’t change the constructor. We created the service and packaged it in a JAR without releasing the source code. So he cannot change what kind of MovieFinder is used in the MovieLister. Our code isn’t configurable and reusable.
The MovieLister class is dependent on both the interface and the implementation of MovieFinder.
Actually, you must try to make it only dependent on the interface.

Dependency injection

That is where dependency injection comes into play.
The idea about dependency injection is that the class itself that is going to use the (MovieFinder) dependency is not responsible for instantiating a concrete implementation of the interface, but the dependent concrete implementation is given to the class by some other object. Martin calls that object an assembler.
This way, the MovieLister class isn’t dependent on the MovieFinderDummy implementation anymore, but only on its MovieFinder interface (it doesn’t have to do an import of the concrete implementation class).

There are several types of dependency injection:

  • Constructor injection
  • Setter injection
  • Interface injection
  • Field injection: This one’s new, using annotations on fields, parameters but also on constructors or setters

You can read all details about each type of injection in Martin Fowler’s article.
I’ll only give an example of setter injection using the Spring framework.

Setter injection with Spring

Taken from the SpringSource website:

The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications – on any kind of deployment platform. A key element of Spring is infrastructural support at the application level: Spring focuses on the “plumbing” of enterprise applications so that teams can focus on application-level business logic, without unnecessary ties to specific deployment environments.

Spring includes:

  • Flexible dependency injection with XML and annotation-based configuration styles
  • Advanced support for aspect-oriented programming with proxy-based and AspectJ-based variants
  • Support for declarative transactions, declarative caching, declarative validation, and declarative formatting
  • Powerful abstractions for working with common Java EE specifications such as JDBC, JPA, JTA and JMS
  • First-class support for common open source frameworks such as Hibernate and Quartz
  • A flexible web framework for building RESTful MVC applications and service endpoints
  • Rich testing facilities for unit tests as well as for integration tests

You can use Spring to wire up all your dependencies using configuration written in Java code, XML or annotations.
Nowadays, Spring supports setter, constructor and field injection. Using XML most people tend to use setter injection. When using annotations, field injection will be preferred.

I’ll show the example using both XML and annotation-based configuration.
Using annotations, you’ll have to change your code to have a different kind of MovieFinder implementation injected into the MovieLister class. You can use qualifiers, but if the third party component developer provided a MovieFinderFileDummy annotated as a @Service with qualifier “main”, you’ll still have to change the @Autowired @Qualifier annotation to use your own qualifier name inside the provided MovieLister class.
Using XML, your configuration is completely separate from your Java code, so you can completely change the configuration at will without altering the source code.
(Correct me if I’m wrong at this point)
You can also use a mix of annotations and XML configuration. For example, define your MovieLister class in XML where you define the name or the qualifier of the MovieFinder bean to use, and use the @Service and @Qualifier annotation in the MovieFinder to specify your concrete implementation.

Spring XML configuration

Using the same example as above, I’ll now use Spring XML configuration.
I’ve changed the name of MovieFinderDummy to MovieFinderXmlDummy to clearly separate both examples.
The MovieLister doesn’t use a constructor anymore for instantiating the MovieFinder implementation, but uses a setter for injection.

public class MovieLister {
    private MovieFinder movieFinder;

    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    ...
}

My Spring XML configuration looks like the following listing:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

	<bean id="movieFinder" class="be.stesch.movie.spring.xml.MovieFinderXmlDummy" />

	<bean id="movieLister" class="be.stesch.movie.spring.xml.MovieLister">
		<property name="movieFinder" ref="movieFinder" />
	</bean>
</beans>

Here I declare a movieFinder bean of type MovieFinderXmlDummy.
I then declare the movieLister bean of type MovieLister to use the movieFinder bean as it’s dependent property. This way Spring will inject a MovieFinderXmlDummy instance in the MovieLister.

The Client then uses the ClassPathXmlApplicationContext to load the Spring application context to be able to get the MovieLister and list all movies with the specified director.

public class Client {
    private static final String MOVIELISTER_BEAN_NAME = "movieLister";

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "META-INF/config/xmlApplicationContext.xml");

        MovieLister movieLister = applicationContext.getBean(MOVIELISTER_BEAN_NAME, MovieLister.class);
        Movie[] movies = movieLister.listMoviesDirectedBy("Steven Spielberg");
        ...
    }
}
Spring annotation configuration

When using annotations, my Spring application context XML configuration file get’s reduced to the following listing:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
						http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<context:annotation-config />
	<context:component-scan base-package="be.stesch.movie.spring.annotations" />
</beans>

As you can see, I don’t define any beans anymore in this XML. I just define that annotations will be used to configure the Spring container, and where to scan for candidate beans.
Again, here I renamed the MovieFinderDummy to MovieFinderAnnotationDummy for clarity and separation in execution.

@Service("movieFinder")
public class MovieFinderAnnotationDummy implements MovieFinder {
    ...

The MovieLister will now be declared as a Service component where the MovieFinder dependency will be Autowired.

@Service("movieLister")
public class MovieLister {
    @Autowired
    @Qualifier("movieFinder")
    private MovieFinder movieFinder;

    ...

You don’t really need to give a name with the @Service annotation, or use the (Spring based) @Qualifier annotation in the MovieLister class, but it’s just to use the same bean names as in the XML example. Without an @Service name and without an @Qualifier Spring will use the class types to perform dependency injection.
The Client works the same, except for using a different Spring configuration file based on annotations.

public class Client {
    private static final String MOVIELISTER_BEAN_NAME = "movieLister";

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "META-INF/config/annotationApplicationContext.xml");

        MovieLister movieLister = applicationContext.getBean(MOVIELISTER_BEAN_NAME, MovieLister.class);
        Movie[] movies = movieLister.listMoviesDirectedBy("Steven Spielberg");
        ...
    }
}

As said, you can mix and match. Make the MovieLister an annotation configured @Service, declare the MovieFinder‘s concrete implementation in the configuration XML itself and don’t use annotations in the MovieFinder implementation class.

If you want to minimize your dependency (import statements) on Spring, you could also use the JSR 330 Standard annotations like @Named instead of @Service, and @Inject instead of @Autowired, like shown in my downloadable source code.
This way, the only import of the Spring framework resides in the Client class, because there your Spring application context has to be set up.
If you create a web application and reference the applicationContext.xml file in your /WEB/INF-web.xml, then you don’t even have a single Spring import in your source code, while still working with Spring.

Service Locator

Now that you have a complete view on dependency injection and Spring, let’s move on to the Service Locator pattern.
The Service Locator has the same goal as dependency injection: to remove the dependency to the implementation from the calling class.
As Martin Fowler’s article states:

The basic idea behind a service locator is to have an object that knows how to get hold of all of the services that an application might need. So a service locator for this application would have a method that returns a movie finder when one is needed.

I like the idea of having a dynamic Service Locator, with a Map containing all services by key. But I can also agree with Martin’s argument that it’s not explicit. The only way of knowing what services are available is by looking at the keys stored in some file or class. So as an example, I made a mix of both.

This is my Service Locator’s code:

public class ServiceLocator {
    public static final String MOVIEFINDER_SERVICE = "movieFinder";

    public static final String MOVIELISTER_SERVICE = "movieLister";

    private static final ServiceLocator instance = new ServiceLocator();

    private final Map<String, Object> services = new HashMap<String, Object>();

    private ServiceLocator() {
    }

    void loadService(String key, Object service) {
        services.put(key, service);
    }

    public static ServiceLocator getInstance() {
        return instance;
    }

    public Object getService(String key) {
        return services.get(key);
    }

    public MovieFinder getMovieFinder() {
        return (MovieFinder) getService(MOVIEFINDER_SERVICE);
    }

    public MovieLister getMovieLister() {
        return (MovieLister) getService(MOVIELISTER_SERVICE);
    }
}

You can see that my Service Locator is a Singleton that has a Map containing two services. The MovieFinder service and the MovieLister service.
To make the ServiceLocator class testable, and to be able to provide the ServiceLocator with different service implementations, I also use a separate Assembler class loading (or putting) serivces in the ServiceLocator‘s services Map.

public class Assembler {
    private static final Assembler instance = new Assembler();

    private Assembler() {
    }

    public static Assembler getInstance() {
        return instance;
    }

    public void configure() {
        ServiceLocator.getInstance().loadService(ServiceLocator.MOVIEFINDER_SERVICE, new MovieFinderServiceLocatorDummy());
        ServiceLocator.getInstance().loadService(ServiceLocator.MOVIELISTER_SERVICE, new MovieLister());
    }
}

I think you can see this Assembler somewhat in the same way like setting up the Spring application context. It instantiates the services, and makes them available to the calling environment (in this case, through a Service Locator).

If the services don’t contain any state that should be retained while working in a class (and they shouldn’t!), then you can call the Service Locator every time you need a service, instead of storing it somewhere in it’s calling class.
The main class (Client) should still call the Assembler (like creating a new ApplicationContext) to configure the application and load services in the Service Locator.

public class Client {
    public static void main(String[] args) {
        Assembler.getInstance().configure();

        MovieLister movieLister = ServiceLocator.getInstance().getMovieLister();
        Movie[] movies = movieLister.listMoviesDirectedBy("Steven Spielberg");
        ...
    }
}

The final clash

Dependency Injection vs. Service Locator

Why all the fuzz of manually creating a Service Locator solution while you have dependency frameworks available like Spring?
Well, you’ll have to decide based on your requirements, your project and your knowledge.

The Service Locator and dependency injection both have their pro’s and their con’s or implications. Both cases make the application code independent of the concrete implementation of the service interface.

  • With dependency injection, no explicit request is required. The service “appears” in or is given to the application class.
  • Dependency injection tends to be hard to understand and hard to debug.
  • With Service Locator every “user” of a service has a dependency on the Service Locator. If this is a problem, use dependency injection.
  • Using dependency injection, dependencies can be more clear.
    With Service Locator you’ll have to search for every use. With dependency injection you can just read the constructor or the setters. Your usage depends on the nature of the application.
  • Dependency injection might make testing easier, but a Service Locator can also be testable if it is correctly designed.
  • If your code is going to be used in applications that are outside the control of the developer, Service Locator is out of the question. Use dependency injection.

My opinion here is that a dependency injection framework like Spring has evolved so much, that issues you might be having with dependency injection are irrelevant, except perhaps being harder to understand and harder to debug. Spring has it’s own testing framework, which is really an easy framework. It offers configurable dependency injection in code using Java, annotations or in XML configuration files. And it offers an entire platform of support classes and API’s to use enterprise grade components in an application that’s not running on an enterprise application server.
Why re-invent the wheel (design a Service Locator framework) if you can use Spring easily?

Constructor vs. setter injection

I’ve always used setter injection. I supose I was taught it that way or was used to it like that. But after reading Martin’s arguments, it makes sense.
He suggests using constructor injection because you need to have valid objects at construction time. So perform the injection using the constructor. Apparently, this advice originates from Kent Beck’s Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method.

Using constructor injection allows you to hide immutable fields from users of your class. If you don’t want the MovieFinder to be changed or set in the MovieLister class while using the application, then don’t create a setter for it. You then have to use constructor injection to use the dependency. This way you can encapsulate the dependencies in your class.
A disadvantage of constructor injection is that constructors might get a lot of parameters quite fast, or that you have to create a lot of overloaded constructors for every way the object might be created. If this is the case, Martin suggests resorting to setter injection. So, first use constructor injection, until things become too complex. Then change that class to setter injection.
I follow him in this aspect.

Code vs. configuration files, and separating code from usage

There, I follow his advice as well, more or less.
Up untill these days I only used dependency injection (Spring) using XML configuration files (in commercial projects). I like this way of configuring an application because it’s completely separate from your code. Some third party user might want to change the way you application works by changing the XML configuration. If a client wants to use Hibernate or JPA instead of the JDBC code that you have written, he just has to create a Hibernate / JPA implementation and change the dependencies in your persistence layer to his Hibernate / JPA DAO’s.
For smaller projects, or projects that stay under your own control, programmatic configuration can be preferred. XML configuration tends to get cluttered and hard to read and maintain.

Nowadays, this is where annotations come in. You can use programmatic configuration in the Java file where it belongs, without having to create a whole bunch of separate XML configuration files.
If your project is going out of your hands at the end, it can be better to make use of XML configuration.

To conclude

  • These days, Service Locator isn’t of much use anymore, except in very small proprietary projects. For the rest, use a good dependency injection framework.
  • Prefer constructor injection over setter injection to have valid objects at creation time, unless the constructor becomes too complex.
  • If your project is going out of your hands or tends to change a lot, use XML configuration. Otherwise, use code or annotations to configure your application.

I hope you have enjoyed this blog post.
As always, please post your comments and advice.
You can find the source code on my Public DropBox: movie-demo.zip

Advertisements

About Steve Schols

I am Steve Schols, a senior Java consultant working for several clients in Belgium. I mainly blog about the Java language and relevant frameworks and technologies. All statements made here are solely my own and do not represent the opinion of my employer, colleagues or my clients.
This entry was posted in Java, Object Oriented Design, Spring and tagged , , , , , , . Bookmark the permalink.

8 Responses to Dependency Injection vs. Service Locator

  1. Pingback: I was wrong: Constructor vs. setter injection « Java Road Tripping

  2. Pingback: I was wrong: Constructor vs. setter injection « Java Road Tripping

  3. porn 24 says:

    This blogs has very fascinating news i enter just about every
    day to read it’s very useful to do my operate.

  4. Kanagavelu Sugumar says:

    This is a nice tutorial and i am curious on assembler. Just one question is it assembler can exist without a service locator and wise versa? Because we always use service locator to get objects right? Please clarify me. Also if try to take printout; it is missing the code in the scroll bar 😦

  5. This is very informative, thank you.

  6. toufeeq khan says:

    Hi
    “If your project is going out of your hands or tends to change a lot, use XML configuration. Otherwise, use code or annotations to configure your application”.What does it mean?
    I have a similar case where i have been told not to use @Autowired annotation for dependency injection and instead I should configure dependencies in Xml file,but the problem i am facing is that project uses spring 4 and jersey 2 and jersey 2 is not able to recognize spring services when I dont use @Autowired annotation.Any guidance will be highly appreciated.Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s