290

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.

jaco0646
  • 15,303
  • 7
  • 59
  • 83
T. Jung
  • 3,327
  • 3
  • 11
  • 19
  • 3
    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 Jun 27 '18 at 22:23
  • 2
    @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- Sep 26 '18 at 23:19

4 Answers4

464

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

Edit: These 3 links mentioned here are for Spring 4.2., for newer version documentation as per 2023 (6.09) see list below

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.


Spring Documentation

Spring 4.2 (from original post)

Spring 6.0.9 (2023 Current Stable version)

Federico Baù
  • 6,013
  • 5
  • 30
  • 38
Vojtech Ruzicka
  • 16,384
  • 15
  • 63
  • 66
  • 45
    It is general not good idea and not nice to tell the world "field injection should be avoided". Show pros and contras and let other to decide oneself ;) Many people have other experiences and own way of looking at things. – alex Oct 06 '16 at 10:18
  • 15
    That may be the case here, but there are other cases where the community has come to a general consensus to discourage something. Take, for example, Hungarian Notation. – Jannik Jan 10 '17 at 21:45
  • 3
    You give some good points as testability and dependency visibility but i am not agree with all. Constructor injection has no drawbacks? Having 5 or 6 fields to inject in class which performs real compositions of call may be desirable. I disagree also with you with immutability. Having final fields is not mandatory to have a class immutable. It is preferable. Which is very different. – davidxxx Jan 12 '17 at 05:50
  • I think you meant "For mandatory dependencies or when aiming for **immutability**" – Alex Terreaux Jun 15 '17 at 22:43
  • @VojtechRuzicka Could you add a source for the "General guideline, as reccomended also by Spring is following: ... Avoid field injection in most of the cases." statement? – Utku Jun 19 '17 at 05:57
  • @Utku Added statement source. – Vojtech Ruzicka Jun 29 '17 at 06:29
  • @VojtechRuzicka I was asking a source from the Spring itself. That is, where does Spring tell us to avoid field injection? – Utku Jun 29 '17 at 07:44
  • Can you use your own blog as a "source"? – Charles Wood Feb 07 '18 at 22:46
  • 2
    I was referring to link at the beginning of the answer which links to the spring docs – Vojtech Ruzicka Feb 08 '18 at 12:24
  • Reading it after 2 years but the further reading link is really awesome, I request you to please update it with one example to understand the things, it can be done with test class example or any other – Ravi Feb 20 '19 at 07:49
  • I would be curious to know if there is any performance issue too. – Arefe Feb 26 '19 at 05:54
  • Clean way of adding DI via constructor: ```@RequiredArgsConstructor(onConstructor_ = {@Inject})``` – Meghana Randad Jul 22 '20 at 05:37
  • Field Injection is way too appealing and I wish I knew the drawbacks early when I started building projects with Spring. How should I approach refactoring a large codebase with thousands of carelessly used field injections? – Aakash Thakur Dec 18 '22 at 04:13
  • You can have constructor injection for new code and for old code that would be a lot of changes impacting a lot of places. You can gradually start to introduce it when you make changes to existing code. Probably safer that to do big bang and potentially impact whole codebase. – Vojtech Ruzicka Dec 18 '22 at 19:36
  • *"You cannot create immutable objects, as you can with constructor injection"* Aren't they set? I thought ```java public class MyService { @Autowired private final MyDependency myDependency; ``` is more or less equivalent to ```java public class MyService { ApplicationContext applicationContext = // initialization private final MyDependency myDependency = applicationContext.getBean("myDependency"); ``` I mean it's not necessarily valid code, but I had the idea that field injections happen on object creation even if the object is created with a no-args constructor – Sergey Zolotarev Apr 27 '23 at 15:04
  • @Jannik: Then the alternatives must be thoroughly explained in those other cases and the common cases where you might want to use it demystified equally thoroughly, or else I say buck the "community" if you're finding that in those other cases you're running into too many contradictions. – The_Sympathizer Jul 04 '23 at 16:27
93

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 do not rely on the reflection mechanism. (This question was asked 30 minutes later. If the author had used constructor injection it would not have 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 introduce an 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.

serv-inc
  • 35,772
  • 9
  • 166
  • 188
Daniel Olszewski
  • 13,995
  • 6
  • 58
  • 65
  • 5
    testability, yes , It was a nightmare for me to mock the field injected beans. Once, I used the contsructor injection, I need not to do any unnecessary mocking – voucher_wolves Jul 11 '18 at 09:39
  • Can you voucher_wolves please give an example of constructor injection and its test. – java dev Dec 06 '22 at 07:52
  • If you want to new object in your testing, it can only be done using constructor injection https://stackoverflow.com/questions/62774713/internal-working-of-field-injection-in-spring-and-why-is-it-not-recommended-to-u I normally use InjectMocks and Mocks. Is using new() in JUnit a good practice? – Abe Dec 12 '22 at 05:08
  • "It is _always_ wrong" - I am skeptical of extreme absolute statements like that, especially after enough times of finding that the code becomes much more convoluted and ultimately never gets produced when you get too absolute and run into an edge case because you're trying to move heaven and earth to get the rule tight. – The_Sympathizer Jul 04 '23 at 16:30
46

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.

alex
  • 8,904
  • 6
  • 49
  • 75
  • 59
    Very ugly constructor with 8 dependencies is actually awesome as it is a red flag that something is wrong, class has too many dependencies and is probably violating single responsibility principle and should be refactored. It is actually a good thing. – Vojtech Ruzicka Oct 06 '16 at 09:22
  • 9
    @VojtechRuzicka it is not nice for sure but sometimes you can not avoid it. – alex Oct 06 '16 at 09:29
  • 5
    I'd say a rule of thumb of 3, let alone 40-50, dependencies for any class should be a sign that you need to refactor. There's no way a class with 40 dependencies is sticking to single responsibility principal or open/close principal. – Amin J Oct 06 '16 at 15:51
  • 7
    @AminJ The rule is great, but reality is different. Company I'm working is over 20 years and we have a lot of legacy code. Refactoring is a good idea, but it cost money. Also I don't know why are are saying it but I didn't mean 40-50 dependencies, I mean 40-50 beans, components, modules... – alex Oct 06 '16 at 18:01
  • 3
    Its good to see an answer take into consideration cost and time into the field vs constructor injection decision. – heez Aug 15 '17 at 13:32
  • 10
    @dit, your situation is clearly one in which technical debt is causing you to make sub-optimal choices. By your own words, you are in a situation where your decision making is significantly influenced by legacy code over 20 years old. When starting out in a new project, would you still recommend field injection, over constructor injection? Maybe you should put a caveat in your answer to indicate in which cases you would choose field injection. – Umar Farooq Khawaja Dec 07 '18 at 10:56
  • 1
    @ dieter is correct here. 8 dependencies is 8 whether from field or constructor. Making them final is good, but has a cost. Those that make hard rules on convention like this tend to have code bases that are more rigid and poorer quality in my experience. Those that have conventions based on the current context of need tend to have better more well behaved code bases. @Umar, I believe you missed the point that its based on decision and preference in context of the code which doesn't make it wrong. – Randy Jul 30 '19 at 20:54
  • @Randy constructor injection has a clear advantage over field injection in that it makes it obvious what dependencies are needed to construct an object. If field injection is being used, the object may not be fully initialized after construction. If there are reasons to choose an approach where a clear advantage is being given up, those reasons should be identified. That was my point. – Umar Farooq Khawaja Aug 05 '19 at 19:02
  • 1
    @Umar I am sorry I was not clear and I believe I understood your point. I am personally not going to make a decision like that based on a generalization, true or otherwise. I am going to look at the codebase/project that I have in front of me and sort out what is best in that context. My point is that the decision can vary based on the context from project to project. – Randy Aug 06 '19 at 21:54
  • @dieter, in practice on a large project, I absolutely feel what you're writing. But you can still, in many cases, apply a facade pattern or potentially consolidate dependencies. As someone who actually had one with lots of dependencies initially, your `DashboardController` needs to simply route requests (I would gather mostly for display). NOT refactoring is usually more expensive over the long term (assuming the business can otherwise stay afloat over the long-term). – riddle_me_this Feb 06 '20 at 00:51
  • 2
    @vphilipnyc Now, since over 2 Years since my answer, I am still sure constructor injection is antipattern for me. It makes the code less readable. All I want is code injection, not instance construction. We are using it also for simple Beans, not only for 'DashboardController'. – alex Feb 06 '20 at 06:36
  • 1
    If your class is expecting 8+ parameters in the constructors, then something is definitely wrong with your implementation. You should re-consider proposed architecture. – Coke Mar 10 '20 at 22:14
  • 1
    @Coke it was just an example. It was customers legacy code and no one have money to redesign the architecture. this is reality. – alex Mar 11 '20 at 06:36
  • There are ways to keep code clean while using constructor DI: one of the way is to use `@RequiredArgsConstructor(onConstructor_ = {@Inject})` – Meghana Randad Jul 22 '20 at 05:36
  • 2
    I agree, they provided the @Autowired notation and tell us not to use it, I can't understand – UnixAgain Jan 08 '21 at 10:06
  • The advantages you express are simply I am too lazy to create constructors, the code is ugly. So there is no compelling reason, either design or performance. For the listed concerns you can use Lombok. – jperis Oct 20 '21 at 08:06
  • 1
    @jperis have you ever worked on a legacy system? Have you ever used Lombok in a complex situation? Please avoid calling people lazy when your main contribution on SO is related to Scrum. – Johannes Mar 08 '22 at 11:33
  • Whatever my contribution is on SO it does not matter. Field injection is simply a wrong option. I worked and work with Lombok. If you have 50 parameters, once again you are doing wrong. Stop hiding behind legacy code to continue making the code worse. – jperis Mar 08 '22 at 15:17
  • @jperis Lombok is anti pattern. The Lombok Code is not Java SE valid code. – alex Mar 13 '22 at 13:06
  • @dieter Lombok is just syntactic sugar nothing else. As long as you know how and when to use it, I cannot see any problem. – jperis Mar 13 '22 at 19:41
3

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 ;)

  • Could you please clarify on all three inject approaches use reflection? I set a breakpoint for constructor inject but did not spot anything reflection-like. – wlnirvana May 01 '21 at 13:34
  • :13, Bleh (com.wujq.cameldemo) newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect) newInstance:62, NativeConstructorAccessorImpl (sun.reflect) newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect) newInstance:423, Constructor (java.lang.reflect) This is callstack from constructor type injection bean - topn entries. – wujek.oczko May 02 '21 at 17:52
  • Please read the following article. Field injection is costlier than other 2 types as it relies on reflection API. https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring – Asanka Siriwardena Feb 04 '23 at 17:01