spring DI

Spring framework is of great importance to Java development. Its core features are IOC (Inversion of Control) and AOP. The most commonly used one is IOC. The dependencies of objects are controlled by Spring to avoid excessive program coupling caused by hard coding.

Differences between the three DI annotations

1 @Autowired

Using the characteristics of

  1. Autowired annotations are provided by the Spring framework
  2. The Autowired annotation gets the Java bean byType first and byName second
  3. The Autowired annotation, along with the Qualifier annotation, distinguishes the names of Java beans, primarily when javabeans of the same type have more than one real
  4. Autowired annotated objects are normally required to be non-null. If null is allowed, the required=false attribute declaration is required
  5. @autowired can be used on variables, setter methods, and constructors

Use process

A) write @autowored on the member variable to be injected so that you don’t need to configure it in the XML file and remove the corresponding setter and getter methods from the program

B. It can also be written on constructors and setters

C, @ the Qualifier

XX in @qualifier (“XXX”) is the name of the Bean, so when @autowired and @qualifier are used together, the auto-injected policy is changed from byType to byName.

Note, however, that @AutoWired can annotate member variables, methods, and constructors, whereas @Qualifier’s annotation objects are member variables, method inputs, and constructor inputs.

2 @Inject

Using the characteristics of

  1. JSR330 (Dependency Injection for Java) : javax.inject.Inject; Realize the injection
  2. @Inject is automatically assembled according to type. If you need to assemble by name, you need to cooperate with @named
  3. Inject @inject can be applied to variables, setter methods, and constructors
  4. Similar to @Autowired usage, it is more common to use @Autowired provided by Spring

Use process

A) @inject can be applied to variables, setters, and constructors, just like @autowired

B, @ Named

@Named(“XXX”) is the name of the Bean, so @inject and @named will change the policy of automatic injection from byType to byName.

3 @Resource

Using the characteristics of

  1. Esource annotations are provided by the JDK and belong to the J2EE specification
  2. The Resource annotation gets the Java bean byname first and byType second
  3. The property name of the Resource annotation is looked up as the name of the Java bean, and the Name parameter, if any, is used to look up the Java bean
  4. If the name attribute is declared in the Resource annotation, the object must be looked up by name, not by type
  5. @resource can be used on variables and setter methods

Use process

A. @resource instance

Differences between the three injection methods

Pay attention to item

  1. Injection methods: Field injection, setter injection, and constructor injection
  2. Spring recommends using setters and constructors to inject Autowired bean objects, so tools such as IDEA will be alerted when using Autowired to inject private properties. The setter methods and constructor injection are more flexible, allowing objects to be used independently of Spring. Private properties can only be automatically injected through the Spring context. Once the injection fails, there is no way to re-inject.
  3. @Resource cannot be used for constructor injection

1 the field injection

@Controller public class FooController { @Autowired //@Inject private FooService fooService; Public List<Foo> listFoo() {return fooservice.list (); }}Copy the code

This is probably the most common injection method. The reason is simple:

  1. The injection method is simple: add the field to be injected, attached@Autowired, can be completed.
  2. Makes the overall code simple and clear, looks beautiful and generous.

Constructor injection

@Controller public class FooController { private final FooService fooService; @Autowired public FooController(FooService fooService) { this.fooService = fooService; }}Copy the code

The recommended injection method in Spring4.x is a little ugly compared to the field injection method, especially when the injection has a large number of dependencies (5 or more), which can cause code bloat.

The benefits of constructor injection are discussed separately later.

3 setter injection

@Controller public class FooController { private FooService fooService; @autowired public void setFooService(FooService FooService) {this. FooService = FooService; }}Copy the code

When Spring3.x was first released, it was recommended to use this type of annotation. Now it is rarely used and is a hassle to write. Spring was recommended for a good reason: the constructor is cumbersome to inject too many parameters, and setters can be used to allow classes to be reconfigured or re-injected later.

Benefits of constructor injection

What does Spring say in the documentation?

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable 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.

The way the constructor is injected ensures that the injected component is immutable and that the required dependencies are not null. In addition, constructor-injected dependencies are always guaranteed to be fully initialized when returned to the client (component) code.

Dependency immutable

Property is decorated with the final keyword

2 The dependency is not null

(Saves us checking for null)

When you want to instantiate a class, the default constructor is not called because the class already implements a constructor with arguments, so you need the Spring container to pass in the required arguments, so there are two cases: 1. If you have arguments of that type -> pass in, OK. 2: There is no parameter of this type. -> An error is reported. So it’s not going to be null, Spring is not going to pass a null in there

If you use field injection, the disadvantage is obvious, because you will never find the NPE without calling it.

3 The system is fully initialized

This can be combined with the non-empty dependency above. Before passing a parameter to the constructor, make sure that the injected content is not empty, and then be sure to call the constructor of the dependent component to complete the instantiation. In Java class loading instantiation, the constructor is the last step (previously, if there is a parent class, the parent class is initialized, then its own member variables, and then the constructor). So everything that comes back is the initial state.

Avoid circular dependencies

Using field injection can lead to circular dependencies where B is injected into A and A is injected into B:

public class A {
    @Autowired
    private B b;
}
​
public class B {
    @Autowired
    private A a;
}
Copy the code

Use the constructor injection, in the spring project started, will be thrown: BeanCurrentlyInCreationException: Requested bean is currently in creation: Is there an unresolvable circular reference? To remind you to avoid circular dependencies;

If field injection is used, an error will not be reported at startup, but only when using the bean.

5 concludes

  1. Guarantee immutable dependencies (final keyword)
  2. Make sure the dependency is not empty (saves us checking it)
  3. Circular dependencies are avoided
  4. When a dependency is used by multiple implementations, it is recommended to use field injection or setter injection to specify the injection type

Q1: As stated in 3.x, won’t the constructor become bloated if I have a large number of dependencies to inject?

In this case, there is too much responsibility in your class, and you need to think carefully about whether you are violating the class’s single responsibility principle to have so many dependencies to inject.

Q2: Are other injection methods not suitable for use?

Existence is reasonable! The setter approach must have been recommended by Spring in the first place for a reason, and one of the advantages of the setter approach is that it allows the class to be reconfigured or re-injected later. In addition, if a dependency has multiple implementations, we can use @Qualifier to select the name to inject in the constructor, or we can manually configure the implementation to be injected using a field or setter.