209
votes

I read in some posts about Spring MVC and Portlets that field injection is not recommended. As I understand it, field injection is when you inject a Bean with @Autowired like this:

@Component
public class MyComponent {
    @Autowired
    private Cart cart;
}

During my research I also read about constructor injection:

@Component
public class MyComponent {
    private final Cart cart;

    @Autowired
    public MyComponent(Cart cart){
       this.cart = cart;
    }
}

What are the advantages and the disadvantages of both of these types of injections?


EDIT 1: As this question is marked as duplicate of this question i checked it. Cause there aren't any code examples neither in the question nor in the answers it's not clear to me if i'm correct with my guess which injection type i'm using.

4
If field-injection is as bad as you describe, why does Spring allow it? Field injection has its own benefits, in making the code more readable and less verbose. If you are disciplined enough in your coding, you can be sure things wouldn't break even if you use field injection.ashes
@ashes Because it was a neat feature at the time, and the implications weren't entirely thought through. The same reason that Date(int,int,int) exists.chrylis -cautiouslyoptimistic-

4 Answers

324
votes

Injection types

There are three options for how dependencies can be injected into a bean:

  1. Through a constructor
  2. Through setters or other methods
  3. Through reflection, directly into fields

You are using option 3. That is what is happening when you use @Autowired directly on your field.


Injection guidelines

A general guideline, which is recommended by Spring (see the sections on Constructor-based DI or Setter-based DI) is the following:

  • For mandatory dependencies or when aiming for immutability, use constructor injection
  • For optional or changeable dependencies, use setter injection
  • Avoid field injection in most cases

Field injection drawbacks

The reasons why field injection is frowned upon are as follows:

  • You cannot create immutable objects, as you can with constructor injection
  • Your classes have tight coupling with your DI container and cannot be used outside of it
  • Your classes cannot be instantiated (for example in unit tests) without reflection. You need the DI container to instantiate them, which makes your tests more like integration tests
  • Your real dependencies are hidden from the outside and are not reflected in your interface (either constructors or methods)
  • It is really easy to have like ten dependencies. If you were using constructor injection, you would have a constructor with ten arguments, which would signal that something is fishy. But you can add injected fields using field injection indefinitely. Having too many dependencies is a red flag that the class usually does more than one thing, and that it may violate the Single Responsibility Principle.

Conclusion

Depending on your needs, you should primarily use constructor injection or some mix of constructor and setter injection. Field injection has many drawbacks and should be avoided. The only advantage of field injection is that it is more convenient to write, which does not outweigh all the cons.


Further reading

I wrote a blog article about why field injection is usually not recommended: Field Dependency Injection Considered Harmful.

65
votes

This is one of the never-ending discussions in software development, but major influencers in the industry are getting more opinionated about the topic and started to suggest constructor injection as the better option.

Constructor injection

Pros:

  • Better testability. You do not need any mocking library or a Spring context in unit tests. You can create an object that you want to test with the new keyword. Such tests are always faster because they not rely on the reflection mechanism. (This question was asked 30 minutes later. If the author had used constructor injection it would have not appeared).
  • Immutability. Once the dependencies are set they cannot be changed.
  • Safer code. After execution of a constructor your object is ready to use as you can validate anything that was passed as a parameter. The object can be either ready or not, there is no state in-between. With field injection you an introduce intermediate step when the object is fragile.
  • Cleaner expression of mandatory dependencies. Field injection is ambiguous in this matter.
  • Makes developers think about the design. dit wrote about a constructor with 8 parameters, which actually is the sign of a bad design and the God object anti-pattern. It does not matter whether a class has 8 dependencies in its constructor or in fields, it is always wrong. People are more reluctant to add more dependencies to a constructor than via fields. It works as a signal to your brain that you should stop for a while and think about your code structure.

Cons:

  • More code (but modern IDEs alleviate the pain).

Basically, the field injection is the opposite.

36
votes

Matter of taste. It is your decision.

But I can explain, why I never use constructor injection.

  1. I don't want to implement a constructor for all my @Service, @Repository and @Controller beans. I mean, there are about 40-50 beans or more. Every time if I add a new field I would have to extend the constructor. No. I don't want it and I don't have to.

  2. What if your Bean (Service or Controller) requires a lot of other beans to be injected? A constructor with 4+ parameters is very ugly.

  3. If I'm using CDI, constructor does not concern me.


EDIT #1: Vojtech Ruzicka said:

class has too many dependencies and is probably violating single responsibility principle and should be refactored

Yes. Theory and reality. Here is en example: DashboardController mapped to single path *:8080/dashboard.

My DashboardController collects a lot of informations from other services to display them in a dashboard / system overview page. I need this single controller. So I have to secure only this one path (basic auth or user role filter).

EDIT #2: Since everyone is focused on the 8 parameters in the constructor... This was a real-world example - an customers legacy code. I've changed that. The same argumentation applies to me for 4+ parameters.

It's all about code injection, not instance construction.

3
votes

One more comment - Vojtech Ruzicka stated that Spring injects beans in such three ways (the answer with the biggest numbers of points) :

  1. Through a constructor
  2. Through setters or other methods
  3. Through reflection, directly into fields

This answer is WRONG - because FOR EVERY KIND OF INJECTION SPRING USES REFLECTION! Use IDE, set breakpoint on setter / constructor, and check.

This can be a matter of taste but it can also be a matter of a CASE. @dieter provided an excellent case when field injection is better. If You're using field injection in integration tests that are setting up Spring context - the argument with testability of the class is also invalid - unless You want to write later on tests to Your integration tests ;)