The advantages and disadvantages of the three methods of Spring annotation dependency injection and the preferred choices

This article is reproduced from the blog garden

When we are using dependency injection, there are usually three ways:

  1. Inject through the constructor;

  2. Inject through the setter method;

  3. Inject through the filed variable;

Code example:

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

Summary of the differences between the three methods:

  1. Constructor-based injection will fix the order of dependency injection; this method does not allow us to create circular dependencies between bean objects. This restriction is actually a benefit of using constructors to inject-when you don’t even notice the use of setters When injecting, Spring can solve the problem of circular dependencies;

  2. Setter-based injection, it will help us inject dependencies only when the object needs to be injected, not at the time of initialization; on the other hand, if you use constructor-based injection, CGLIB cannot create a proxy, forcing you to use Interface-based proxy or virtual parameterless constructor.

  3. I believe that many students choose to directly write annotations on member variables for injection. As we have seen, this method looks very good, short, highly readable, does not require redundant code, and is easy to maintain;

Disadvantages:

  1. When we use the constructor to inject, one of the more obvious shortcomings is: if we need to inject a lot of objects, our constructor will appear very redundant and unsightly, which greatly affects the beauty and readability. It is also more difficult to maintain;

  2. When we choose the setter method to inject, we cannot make the object final;

  3. When we implement injection on the field variable

    a. This does not conform to the JavaBean specification, and is likely to cause a null pointer;

    b. At the same time, the object cannot be marked as final;

    c. The class is highly coupled with the DI container, we cannot use it externally;

    d. The class cannot be instantiated without reflection (for example, in a unit test), you need to instantiate it with a DI container, which is more like an integration test;


    来自Spring官方文档的建议:
    Etc. 1️⃣In Spring 3.x, the Spring team recommends that we use setters to inject:

    Roughly speaking, a large number of constructor parameters can be very cumbersome, especially when attributes are optional. The setter method allows the objects of the class to be reconfigured or reinjected later. Providing all dependencies means that the object always returns a fully initialized client client (call). The disadvantage is that objects become less suitable for reconfiguration and reinjection.

    2️⃣In Spring 4.x, the Spring team no longer recommends that we use setters for injection, instead of constructor

    The Spring team usually recommends using the constructor for injection, because it allows an application component to be implemented as an immutable object and ensures that the required dependencies are not empty. In addition, the constructor injection component always returns a fully initialized client client (call). Note that a large number of constructor parameters is a bad code habit and looks bad, which means that the class may have too many responsibilities and should be refactored to better address the proper separation of concerns.
    The setter method should only be used primarily for optional dependencies where reasonable default values ​​can be specified in the class. Otherwise, non-null checks should be performed wherever dependencies are used. One advantage of setter injection is that the setter method allows the object of the class to be reconfigured or reinjected later.

New features
of Spring 4.3 : After Spring 4.3, if there is only a single constructor in our class, then Spring will implement an implicit automatic injection, the code:

@Service
public class FooService {
    
    

    private final FooRepository repository;

    @Autowired
    public FooService(FooRepository repository) {
    
    
        this.repository = repository
    }
}

After Spring 4.3:

@Service
public class FooService {
    
    

    private final FooRepository repository;

    public FooService(FooRepository repository) {
    
    
        this.repository = repository
    }
}

As we can see, I removed the @Autowired annotation on the constructor. After testing, I found that the program can run normally and the repository dependency has been successfully injected.

to sum up:

  1. Mandatory dependencies or when the target is immutable, use constructor injection (it should be said that the constructor is used to inject as much as possible)

  2. Optional or changeable dependencies use setter injection (it is recommended to use the constructor combined with the setter to inject)

  3. In most cases, avoid field injection (I feel that most students may have objections. After all, this method is very easy to write, but its disadvantages are indeed far greater than these advantages)

  4. Students of Spring 4.3+ can try the implicit injection of the constructor. After injection in this way, our code is more elegant and independent, and the dependency on Spring is reduced.

Guess you like

Origin blog.csdn.net/qq_40084325/article/details/111387068