Spring Field vs Setter vs Constructor Injection

Lately, I have been immersed in the world of Java and its various frameworks, tools and language features. I’ve also recently discovered that Java is not cool. I found myself at a gathering of developers some time ago, where they attempted to proselytise me into the ruby cult family. Unfortunately, since puberty, I have had trouble growing enough facial hair to be seen as ‘one of them’.

In this Java world, it seems that the Spring framework is king for large applications. And their IoC container is very useful for inserting dependencies into classes where they are needed. Currently, there seem to be 2 ways of mapping interfaces to their desired implementations: an xml configuration file, and using annotations in the classes.

Personally, I’m not a fan of either, but I’m REALLY not a fan of the XML configuration. The classes that require the dependencies are cleaner, but if a class name were to change, or the properties were to change, one has to remember to update the XML files with the updated dependencies. I find this cumbersome. Others may disagree.

The other option is the annotations. This way, the Spring framework automagically finds the implementation of a dependency based on an annotation. For example, if one has a book repository interface it may look something like this:

public interface BookRepository { 
    List<Book> findAllBooks(); 
}

The implementation of that interface may look like this.

@Component 
public class BookRepositoryImpl implements BookRepository { 

    @Override 
    public List<Book> findAllBooks() { 
        List<Book> books = new ArrayList<>(); 
        books.add(new Book()); 
        books.add(new Book()); 
        return books; 
    } 
}

The @Component annotation before the class declaration tells Spring that this class is a candidate for injection when dependencies are automagically configured.

To use this in another class, the @Autowire annotation is used, to let Spring know that this dependency should be injected by Spring. There are three ways to do it.

Field injection looks like this:

public class BookFinder { 

    @Autowire 
    private BookRepository bookRepository; 
}

The annotation above the private field within the BookFinder class will let Spring know that the bookRepository field dependency should be injected somehow.

Setter injection looks like this:

public class BookFinder { 
    private BookRepository bookRepository; 

    @Autowire 
    @Required 
    public setBookRepository(BookRepository bookRepository) { 
        this.bookRepository = bookRepository; 
    } 
}

In the example above, the BookRepository dependency will be injected through the setter (configured to do so by the @Autowire annotation above the setter). The @Required annotation tells the configuration that it is mandatory, and will therefore be injected when the class is initialised.

Lastly, there is constructor injection which looks like this:

public class BookFinder { 
    private BookRepository bookRepository; 

    @Autowire public BookFinder(BookRepository bookRepository) { 
        this.bookRepository = bookRepository; 
    } 
}

Here, the dependency is passed through the constructor when the class is initialised (configured by the @Autowire attribute above the constructor).

Now the @Autowire annotation is not ideal because now every class is tightly coupled to the Spring framework. Which is not ideal. But it will have to work for now. But which form of injection is best? In my opinion – constructor injection. Why? Because more time is spent reading the code we write than actually writing the code, and therefore clarity should be first prize before perceived immediate efficiency.

The field injection method doesn’t show that the class has dependencies. It has private fields. And an @Autowire attribute to make someone familiar with the Spring IoC container know that those private fields are dependencies which are injected in. This makes the class harder to understand. It is also harder to test because one is now dependant on testing libraries and frameworks that automagically inject mocks and stubs as dependencies. This results in frustrated people trying to understand it to make modifications. This doesn’t contribute to world peace.

Setter injection seems to be the method preferred by the writers of the Spring IoC Container documentation. At least here it explicitly shows that the dependencies are injected into the class. But it isn’t explicitly clear that all these dependencies are required by the class. Therefore, when writing tests, and passing dependencies into the class, or using the class’ interface from another class, one has to be aware of the internal workings of the class. This is also not ideal.

Constructor injection makes all the dependencies a class requires explicit. This makes a class ‘complete’ when it is created. This also makes a class easier to test. Some posts on the internets have said that if a class has many dependencies, the list of constructor arguments become too large. But other posts on the internets (which I agree with) have said that if your class has too many dependencies, then maybe your class does too much.

I think I have written too much. Thoughts? Agree? Disagree?

Patrick Kayongo

I create and maintain software. Pan-African.

Johannesburg, South Africa