A logo showing the text blog.marcnuri.com
Español
Home»Java»Field injection is not recommended – Spring IOC

Recent Posts

  • Fabric8 Kubernetes Client 7.2 is now available!
  • Connecting to an MCP Server from JavaScript using AI SDK
  • Connecting to an MCP Server from JavaScript using LangChain.js
  • The Future of Developer Tools: Adapting to Machine-Based Developers
  • Connecting to a Model Context Protocol (MCP) Server from Java using LangChain4j

Categories

  • Artificial Intelligence
  • Front-end
  • Go
  • Industry and business
  • Java
  • JavaScript
  • Legacy
  • Operations
  • Personal
  • Pet projects
  • Tools

Archives

  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • August 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • February 2020
  • January 2020
  • December 2019
  • October 2019
  • September 2019
  • July 2019
  • March 2019
  • November 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • December 2017
  • July 2017
  • January 2017
  • December 2015
  • November 2015
  • December 2014
  • March 2014
  • February 2011
  • November 2008
  • June 2008
  • May 2008
  • April 2008
  • January 2008
  • November 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007

Field injection is not recommended – Spring IOC

2018-02-21 in Java tagged Dependency Injection / Inversion of control (IoC) / Java / SOLID / Spring Framework by Marc Nuri | Last updated: 2021-08-07
Versión en Español

Introduction

When running a static code analysis tool or inspecting/analyzing your code from your IDE, you may have encountered the following warning regarding your @Autowired fields:

Field injection is not recommended
Field injection is not recommended (IntelliJ IDEA warning screenshot)
Field injection is not recommended (IntelliJ IDEA warning screenshot)

This post shows the different types of injections available in Spring and what are the recommended patterns to use each of them.

Injection types

Although current documentation for spring framework (5.0.3) only defines two major types of injection, in reality there are three;

  • Constructor-based dependency injection
  • Setter-based dependency injection
  • Field-based dependency injection

The latter is the one which the static code analysis tool complains about, but is regularly and extensively used.

You can even see this injection method on some of Spring guides although being discouraged in the documentation:

Spring guide with autowired field

Constructor-based dependency injection

In constructor-based dependency injection, the class constructor is annotated with @Autowired and includes a variable number of arguments with the objects to be injected.

1@Component
2public class ConstructorBasedInjection {
3
4    private final InjectedBean injectedBean;
5
6    @Autowired
7    public ConstructorBasedInjection(InjectedBean injectedBean) {
8        this.injectedBean = injectedBean;
9    }
10
11}

The main advantage of constructor-based injection is that you can declare your injected fields final, as they will be initiated during class instantiation. This is convenient for required dependencies.

Setter-based dependency injection

In setter-based dependency injection, setter methods are annotated with @Autowired. Spring container will call these setter methods once the Bean is instantiated using a no-argument constructor or a no-argument static factory method in order to inject the Bean’s dependencies.

1@Component
2public class ConstructorBasedInjection {
3
4    private InjectedBean injectedBean;
5
6    @Autowired
7    public void setInjectedBean(InjectedBean injectedBean) {
8        this.injectedBean = injectedBean;
9    }
10
11}

Field-based dependency injection

In field-based dependency injection, fields/properties are annotated with @Autowired. Spring container will set these fields once the class is instantiated.

1@Component
2public class ConstructorBasedInjection {
3
4    @Autowired
5    private InjectedBean injectedBean;
6
7}

As you can see, this is the cleanest way to inject dependencies as it avoids adding boilerplate code and there is no need to declare a constructor for the class. The code looks nice, neat and concise but as the code inspector already hinted us, there are some drawbacks to this approach.

Field-based dependency injection drawbacks

Disallows immutable field declaration

Field-based dependency injection won’t work on fields that are declared final/immutable as this fields must be instantiated at class instantiation. The only way to declare immutable dependencies is by using constructor-based dependency injection.

Eases single responsibility principle violation

As you know, in object-oriented computer programming, the SOLID acronym defines five design principles that will make your code understandable, flexible and maintainable.

The S in SOLID stands for single responsibility principle, meaning that a class should only be responsible for a single part of the functionality of the software application and all its services should be aligned narrowly with that responsibility.

With field-based dependency injection, it’s really easy to have lots of dependencies in your class and everything will look just fine. If constructor-based dependency injection is used instead, as more dependencies are added to your class, the constructor grows bigger and bigger and code starts to smell, sending clear signals that something is wrong.

Having a constructor with more than ten arguments is a clear sign that the class has too many collaborators and that maybe is a good time to start splitting the class into smaller and more maintainable pieces.

So although field-injection is not directly responsible for breaking the single responsibility principle it surely enough helps by hiding signals that otherwise would be really clear.

Tightly coupled with dependency injection container

The main reason to use field-based injection is to avoid the boilerplate code for getters and setters or creating constructors for your class. In the end, this means that the only way these fields can be set are by Spring container instantiating the class and injecting them using reflection, otherwise the fields will remain null and your class will be broken/useless.

The dependency injection design pattern separates the creation of class dependencies from the class itself transferring this responsibility to a class injector allowing the program design to be loosely coupled and to follow the Single responsibility and Dependency inversion principles (again SOLID). So in the end the decoupling achieved for the class by autowiring its fields is lost by getting coupled again with the class injector (in this case Spring) making the class useless outside of a Spring container.

This means that if you want to use your class outside the application container, for example for unit testing, you are forced to use a Spring container to instantiate your class as there is no other possible way (but reflection) to set the autowired fields.

Hidden dependencies

When using a dependency injection pattern, affected classes should clearly expose these dependencies using a public interface either by exposing the the required dependencies in the constructor or the optional ones using methods (setters). When using field-based dependency injection, the class is inherently hiding these dependencies to the outside world.

Conclusion

We’ve seen that field-based injection should be avoided whenever possible due to its many drawbacks however elegant it may seem. The recommended approach is then to use constructor-based and setter-based dependency injection. Constructor-based injection is recommended for required dependencies allowing them to be immutable and preventing them to be null. Setter-based injection is recommended for optional dependencies.

An image of syringes to symbolize injection
An image of syringes to symbolize injection
Twitter iconFacebook iconLinkedIn iconPinterest iconEmail icon

Comments in "Field injection is not recommended – Spring IOC"

  • Avatar for rw
    rw
    2018-09-10 03:59
    great post
  • Avatar for Omar FENDRI
    Omar FENDRI
    2019-07-04 16:08
    Thanks!
  • Avatar for Tomasz
    Tomasz
    2019-10-15 14:20
    The most valuable thing that I learnt this week. Thanks!
  • Avatar for Binh Thanh Nguyen
    Binh Thanh Nguyen
    2020-02-21 17:25
    Thanks, nice explanation
  • Avatar for Yavuz Tas
    Yavuz Tas
    2020-02-28 19:09
    Great article and very good points about what might be the drawbacks of field injection.

    However, I believe most of them are design problems, not a problem with the type of injection. Maybe the most sensible one is the immutability issue. If we ever had a chance to inject in final fields, it would be great.

    Again, it's also not a big problem because almost every bean we inject are singletons and we don't initialize them more than once.

    Cheers
  • Avatar for Rogério Liesenfeld
    Rogério Liesenfeld
    2020-11-19 21:12
    All four "field-based DI drawbacks" presented are non-sensical:

    1. "Disables immutable field declaration": this falsely assumes that developers would be prone to manually re-assing annotated injected fields. From personal experience (and just common sense), I can say this never happens. A team would have bigger issues if individual developers were making such a gross mistake.

    2. "Eases SRP violation": so, a disadvantage of constructor DI (having to write extra code) is actually an advantage, because it would supposedly discourage developers from adding too many dependencies? Seriously...

    3. Tightly coupled with DI container: this assumes that developers would actually write code that manually wires lots of "beans" and their dependencies together, rather than letting a tool/library do it for them. In practice, if a project uses a DI container, you expect to be able to use it or some other tool (personally, I use the JMockit library for that in JUnit tests), rather than writing potentialy thousands of lines of wiring code. Would be better then to avoid DI entirely.

    4. "Hidden dependencies": this misses the fact that said dependencies normally are *internal* to the bean/component where they are injected into, and completely unknown to clients of the bean/component. That is, it makes no sense to expose such dependencies in the public API - as they actually *are* meant to be "hidden".
    • Avatar for Marc Nuri
      Marc Nuri
      2020-11-24 09:13
      Hi Rogério,

      Thanks for your comments and insights.

      Just as a reminder, this warning was introduced by the Spring Team themselves, and this post is just an explanation of what that may mean according to my opinions.

      1. Teams are very diverse and skills may vary. I can tell you I've seen this happening on real projects. Unfortunately, good practices are not that extended across all companies. "A team would have bigger issues if individual developers were making such a gross mistake", exactly, so in order to prevent further issues, this may be a good start.

      2. Yep, same as having classes with more than 200 lines is an automatic code-smell. If you have Sonar enabled with default rules, you'll also get an extra warning if your constructor exceeds 7 parameters (java:S107).

      3. If you have something decoupled from the start, it might be easier to migrate or use the same library across different frameworks. With the rise of Quarkus, and Micronaut, I'm sure many would probably benefit from implementations that are agnostic of their application container. IMHO having to write tests that rely on DI is also a clear disadvantage and will probably affect performance.

      4. The term expose here is used in terms of contract and not in terms of encapsulation. e.g. many IDEs warn you about missing bean declarations which are required for injections in another Bean. So if your component has constructor-based injection of certain interfaces, you know that somewhere in your application configuration you'll need to declare Beans implementing said dependencies.

      I insist, these are just my opinions and, like everything on the Internet, should be taken with a grain of salt.

      I use JMockit in some projects, I really appreciate you sharing your opinions.
    • Avatar for Marc Nuri
      Marc Nuri
      2020-11-24 11:13
      Just jumped onto this https://softwareengineering.stackexchange.com/questions/300706/dependency-injection-field-injection-vs-constructor-injection which seems especially ;) related to the topic.
  • Avatar for Pradeep Siddagangaiah
    Pradeep Siddagangaiah
    2021-01-24 17:33
    Good explanation

Post navigation
Spring Data MongoDB: Custom repository implementationDocker container as a Linux system service
© 2007 - 2025 Marc Nuri