reproduced in https://www.cnblogs.com/chansblogs/p/8343930.html
When we use dependency injection, there are usually three ways:
1. Inject through the constructor;
2. Inject through the setter method;
3. Inject through the filed variable;
So are they any different? Which way should I choose better?
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 limitation is actually a benefit of using constructors to inject - when you don't even notice using setter injection, 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 use interface-based proxies or virtual parameterless constructors.
3. I believe that many students choose to use annotations directly on member variables to inject. As we can see, this method looks very good, short, highly readable, does not require redundant code, and is easy to maintain;
shortcoming:
1. When we use the constructor to inject, one of the obvious disadvantages is: if we need to inject a lot of objects, our constructor will appear very redundant and unsightly, which greatly affects the appearance 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 the 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. A class cannot be instantiated without reflection (such as in unit testing), you need to use a DI container to instantiate it, which is more like an integration test;
... etc.
Advice from official Spring documentation
In Spring 3.x, the Spring team recommends that we use setter s to inject:
Roughly speaking, a large number of constructor parameters can be unwieldy, especially when properties are optional. setter methods allow objects of the class to be reconfigured or reinjected at a later time. Providing all dependencies means that the object always returns a fully initialized state to the client (call). The downside is that objects become less amenable to reconfiguration and reinjection.
In Spring 4.x, the Spring team no longer recommends that we use setter s for injection, but instead constructor s:
The Spring team generally recommends using the constructor for injection, as it allows an application component to be implemented as an immutable object and ensures that the required dependencies are not null. In addition, the constructor-injected component always returns a fully initialized client client (call). As a side note, a large number of constructor parameters is a bad code practice and looks bad, meaning that the class may have too many responsibilities and should be refactored to better address proper separation of concerns.
setter methods should only be used primarily for optional dependencies where sensible defaults can be specified in the class. Otherwise, non-null checks should be performed everywhere the dependency is used. One benefit of setter injection is that setter methods allow objects of the class to be reconfigured or re-injected at a later time.
Next, insert a new feature 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 above:
Before:
@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 } }
Even if the @Autowired annotation on the constructor is removed, after testing, it is found that the program can run normally and the dependencies of the repository are successfully injected