DI

1.Constructor vs Setter Injection

So the Field injection may not be the way to go. What's left? Setters and Constructors. Which one should be used?

1.1Setters

Setters should be used to inject optional dependencies. The class should be able to function when they are not provided. The dependencies can be changed anytime after the object is instantiated. That may on may not be an advantage depending on the circumstances. Sometimes it is desirable to have an immutable object. Sometimes it is good to change the object's collaborators at runtime - such as JMX managed MBeans.

The official recommendation fromSpring 3.x documentationencourages the use of setters over constructors:

The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management throughJMX MBeansis a compelling use case.

Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code in a totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.

1.2Constructors

Constructor injection is good for mandatory dependencies. Those, which are required for the object to function properly. By supplying those in the constructor, you can be sure that the object is ready to be used the moment it is constructed. Fields assigned in the constructor can also be final, allowing the object to be either completely immutable or at least protect its required fields.

One consequence of using a constructor to provide dependencies is that circular dependency between two objects constructed in such way is no longer possible (unlike with setter injection). That is actually a good thing rather than limitation as circular dependencies should be avoided and are usually a sign of a bad design. This way such a practice is prevented.

Another advantage is that if using spring 4.3+, you can completely decouple your class from DI frameworks. The reason is that Spring now supportsimplicit constructor injectionfor one constructor scenarios. That means you no longer need DI annotations in your classes. Of course, you could achieve the same with explicitly configuring DI in your spring configs for given class, this just makes this whole lot easier.

As of Spring 4.x, the official recommendation fromSpring documentationchanges and setter injection is no longer encouraged over constructor:

The Spring team generally advocates constructor injection as it enables one to implement application components asimmutable objects_and to ensure that required dependencies are not null. Furthermore, constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a_bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later.

1.3UPDATE: IntelliJ IDEA support

Since this article was published, IDEA introduced some sweet support for detecting and easily fixing Field Injection. It can automatically remove the@Autowiredannotation from the field and instead create a constructor with@Autowireddependency, effectively replacing field injection with constructor injection.

1.4Conclusion

Field injection should be mostly avoided. As a replacement, you should use either constructors or methods to inject your dependencies. Both have its advantages and disadvantages and the usage depends on the situation. However, as those approaches can be mixed, it is not an either-or choice and you can combine both setter and constructor injection in one class. Constructors are more suitable for mandatory dependencies and when aiming for immutability. Setters are better for optional dependencies.

2. Field Injection

https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/

eg:

Constructor:

private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public DI(DependencyA dependencyA, DependencyB dependencyB, DependencyC dependencyC) {
    this.dependencyA = dependencyA;
    this.dependencyB = dependencyB;
    this.dependencyC = dependencyC;
}

Setter:

private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public void setDependencyA(DependencyA dependencyA) {
    this.dependencyA = dependencyA;
}

@Autowired
public void setDependencyB(DependencyB dependencyB) {
    this.dependencyB = dependencyB;
}

@Autowired
public void setDependencyC(DependencyC dependencyC) {
    this.dependencyC = dependencyC;
}

Field

@Autowired
private DependencyA dependencyA;

@Autowired
private DependencyB dependencyB;

@Autowired
private DependencyC dependencyC;

Field Dependency Injection Considered Harmful

  1. Single Responsibility Principle Violation(may add too many dependencies)

  2. Dependency Hiding: When the class is no longer responsible for obtaining its dependencies, it should clearly communicate them using public interface - methods or constructors. This way it is clear what the class requires and also whether it is optional(setters) or mandatory(constructors).

  3. DI Container Coupling: when injecting directly into fields, you provide no direct way of instantiating the class with all its required dependencies.

  4. Immutability: Unlike constructor, field injection cannot be used to assign dependencies to final fields effectively rendering your objects mutable.

Last updated