The @Autowired annotation in Spring explains how it works on methods and properties.

@Autowired indicates whether a property requires dependency injection and can be used on properties, ordinary methods, and constructors. The required attribute in the annotation is true by default. If no object can be injected into the attribute, an exception will be reported;

When @Autowired is added to a property, spring will find the bean object from the ioc container and inject it into the property. If multiple Bean objects of this type are found, one will be confirmed from the multiple Bean objects based on the name of the property;

@Autowired is written on the set() method. In spring, according to the parameter type of the method, it will find the Bean object of this type from the ioc container and inject it into the line parameter of the method, and automatically call the method through reflection (the method modified by @Autowired must be will be executed), so it is generally used in the set method and not in the ordinary method;

@Autowired is used in the constructor method: according to the formal parameters and formal parameter names of the constructor method, find the Bean object of this type from the ioc container, inject it into the formal parameters of the constructor method, and execute the method;

  //构造方法
    @Autowired
    public Bean03(Bean04 bean04) {
    
    
        System.out.println("11111111111111");
    }
    //属性上
    @Autowired
    Bean04 bean04;
  
    //set方法
    @Autowired
    public void setBean04(Bean04 bean) {
    
    
        this.bean04 = bean;
    }
    //普通方法
   @Autowired
    public void commonMethod(Bean04 bean04){
    
    
        System.out.println("普通方法的执行");
    }

Details of @Autowired usage on constructors

If @Autowired is used on multiple constructors on the same class, an error will be reported by default;

Solution: You can set the required attribute of @Autowired to false. At this time, spring will choose which construction method to use;

Spring’s selection rules in the above situation:

1. Priority will be given to those with more parameters.

(First find multiple beans of this type by Type, and then inject them by Name)

2. If multiple types of beans cannot be injected according to ByName, consider injecting the one with the fewest parameters, and so on;

3. When the number of parameters is the same and ByName can also be injected, select according to the order in which the constructor is written;

@Autowired annotation acts on methods

(1) If this method has parameters, it will use the autowired method to find whether there are such parameters in the container.

(2) This method will be executed

Insert image description here

So if you put @Autowired on the setter method, it is equivalent to assigning values ​​to the properties of the object.

@Autowired annotation acts on properties

That is, injecting a value into the property when creating an object in the container has the same effect as @Autowired in the setter method.

Usage and injection rules of @Autowired annotation

As a Spring developer, you must be very familiar with the @Autowired annotation. As the name suggests, automatic assembly means that Spring will automatically assemble the elements we mark as @Autowired. Instead of guessing, it is better to look at its definition:

@Target({
    
    ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    
    
  
  boolean required() default true;
  
}

Obviously this annotation can be used on constructors, variable fields, methods, annotation types and method parameters. The document describes this: Mark a constructor, variable field, setter method, and config method to be automatically assembled by the Spring DI tool. In other words, during the process of creating a bean in Spring, the bean we need that is already in the Spring IOC container will be automatically injected into the constructor, variable field, method and method parameter marked with @Autowired annotation in the bean, without having to We do it manually, and the injected beans are all single instances, that is, both beans depend on the third bean, then the third bean injected in these two beans will be the same bean (the address pointed to in the JVM same).

There is a required attribute in the @Autowired annotation. This attribute defaults to true. When it is true, it means to search for the corresponding bean in Spring IOC. If it cannot be found, an error will be reported. If it is false, it means to go to Spring IOC. Search for the corresponding bean. If it cannot be found, it will be ignored and no more injection will be performed.

Injection rules for the @Autowired annotation: Injection is performed by type by default. If there are two or more beans of the same type in the IOC container, injection is performed based on the name of the bean. If there is no bean with a specified name, an error will be reported.

You can use @Qualifier("wheel") to use the bean with the specified id, or you can add the @Primary annotation when injecting the bean, and add a bean first. The rules are as follows:

If @Qualifier("wheel") is specified, it will be added according to the specified bean id (highest priority). If it cannot be found, an error will be reported directly. If @Qualifier is not added but @Primary annotation is added, the bean marked with @Primary annotation is added first. If there is both @Qualifier annotation and @Primary annotation, it will be injected according to the bean id specified by @Qualifier. If it is not found, an error will be reported directly.

Let's take a look at the usage of @Autowired:

1. Used in variable fields

I believe everyone already knows this. Spring will help us inject the beans we want. See the following example:

@Component
public class Wheel {
    
    
  
}
  
@Component
public class Car {
    
    
  
    @Autowired
    private Wheel wheel2;
  
    public Wheel getWheel() {
    
    
        return wheel2;
    }
  
    public void setWheel(Wheel wheel2) {
    
    
        this.wheel2 = wheel2;
    }
}
  
@ComponentScan({
    
    "it.cast.circularDependency"})
public class AutowiredConfig {
    
    
  
}

Test below. The printed result shows that the Wheel class can be obtained, indicating that the @Autowired annotation is injected according to the type when there is only one type of bean in the IOC container.

    @Test
    public void AutowiredConfigTest(){
    
    
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AutowiredConfig.class);
  
        Car bean = context.getBean(Car.class);
        System.out.println(bean.getWheel());
    }
  
//打印结果:
//   it.cast.circularDependency.Wheel@3eb25e1a

Let's take a look at the situation when there are two Wheel type beans in the IOC container. Transform the Wheel class and add an attribute identifier to record which Wheel bean is injected into the Car class. Add a bean to the AutowiredConfig configuration class. The name defaults to the method name, which is wheel1.

@Component
public class Wheel {
    
    
    private int num = 2;   //通过包扫描的方式注入的bean的num值为2
  
    public int getNum() {
    
    
        return num;
    }
  
    public void setNum(int num) {
    
    
        this.num = num;
    }
}
  
@Component
public class Car {
    
    
  
    @Autowired
    private Wheel wheel3;//将变量名改成wheel3,IOC容器中Wheel类型的bean的名称只有wheel和wheel1
  
    public Wheel getWheel() {
    
    
        return wheel3;
    }
  
    public void setWheel(Wheel wheel3) {
    
    
        this.wheel3 = wheel3;
    }
}
  
  
@Configuration
@ComponentScan({
    
    "it.cast.circularDependency"})
public class AutowiredConfig {
    
    
  
    @Bean
    public Wheel wheel1(){
    
     
        Wheel wheel = new Wheel();//通过配置类注入bean的方式num值为0
        wheel.setNum(0);
        return wheel;
    }
}

At this time, there are two Wheel type beans in Spring IOC. When Car injects a Wheel type bean, it will look for it based on the variable name wheel3, which means it will look for a bean with type Wheel and name wheel3, which is obviously If it cannot be found, an error will be reported.

Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name ‘car’:
Unsatisfied dependency expressed through field ‘wheel3’;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type ‘it.cast.circularDependency.Wheel’ available:
expected single matching bean but found 2: wheel,wheel1

org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name ‘car’: Unsatisfied dependency expressed through field ‘wheel3’;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type ‘it.cast.circularDependency.Wheel’ available:
expected single matching bean but found 2: wheel,wheel1

The above is the error log printout. The general meaning is that when creating a bean named car, attribute injection cannot be completed for the variable field wheel3 because two beans are found, namely wheel and wheel1.

If we replace wheel3 in Car with wheel, the injection can be completed, and the injected bean is the bean injected into the IOC through package scanning:

@Component
public class Wheel {
    
    
    private int num = 2;   //通过包扫描的方式注入的bean的num值为2
  
    public int getNum() {
    
    
        return num;
    }
  
    public void setNum(int num) {
    
    
        this.num = num;
    }
}
  
@Component
public class Car {
    
    
  
    @Autowired
    private Wheel wheel;//将变量名改成wheel1,IOC容器中Wheel类型的bean的名称只有wheel和wheel1
  
    public Wheel getWheel() {
    
    
        return wheel;
    }
  
    public void setWheel(Wheel wheel3) {
    
    
        this.wheel = wheel;
    }
}
  
  
@Configuration
@ComponentScan({
    
    "it.cast.circularDependency"})
public class AutowiredConfig {
    
    
  
    @Bean
    public Wheel wheel1(){
    
     
        Wheel wheel = new Wheel();//通过配置类注入bean的方式num值为0
        wheel.setNum(0);
        return wheel;
    }
}

Print the num value in the test class to see which bean is injected:

    @Test
    public void AutowiredConfigTest(){
    
    
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AutowiredConfig.class);
  
        Car bean = context.getBean(Car.class);
        System.out.println(bean.getWheel().getNum());
    }
  
   //打印结果:
   //    2

Then the injection rules mentioned above are verified: injection is performed by type by default. If there are two or more beans of the same type in the IOC container, injection is performed according to the name of the bean. If there is no bean with a specified name, an error will be reported. .

The @Autowired annotation can also solve the problem of circular dependency when used in the variable domain. The circular dependency problem is that the A object is injected into the B object, and the B object is injected into the A object. Circular dependencies should often be questioned when interviewing about Spring knowledge. , Regarding the issue of circular dependencies, it will be updated in a later blog.

2.@Autowired annotation is used on the constructor

There are several points that require special attention when using @Autowired in constructors:

1. @Autowired annotation on the constructor cannot solve the problem of circular dependency construction

2.@Autowired can be annotated on multiple constructors of the same class, but the required attributes must all be false. When one of required is true, other constructors are not allowed to be marked with @Autowired annotation, even if the required attribute is false. no.

@Component
public class A {
    
    
    private B b;
    private C c;
  
    @Autowired
    public A(B b, C c) {
    
    
        System.out.println("b=" + b + ", c=" + c);
        this.b = b;
        this.c = c;
    }
}
  
@Component
public class B {
    
    
  
}
  
@Component
public class C {
    
    
}
  
//打印结果:
//  b=it.cast.circularDependency.B@68e965f5, c=it.cast.circularDependency.C@6f27a732

@Autowired is marked on the constructor. During the creation process of B, the required injected beans will be obtained from Spring IOC to complete the creation of B. In fact, in the case of only one constructor, @Autowired does not need to be added because Spring has the ability to automatically infer constructors internally. If you want to know about automatic inference constructors, you can search on Baidu.

Let's look at a case of constructor circular dependency:

@Component
public class C {
    
    
    private B b;
  
    public C(B b) {
    
    
        this.b = b;
    }
}
  
@Component
public class B {
    
    
    private C c;
  
    public B(C c) {
    
    
        this.c = c;
    }
}

Spring currently cannot resolve circular dependencies of constructors, so pay special attention when using them in projects. Error log:

org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name ‘a’ defined in file
[E:\IdeaProjects\javaBasis\spring\target\classes\it\cast\circularDependency\A.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name ‘b’ defined in file
[E:\IdeaProjects\javaBasis\spring\target\classes\it\cast\circularDependency\B.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name ‘c’ defined in file
[E:\IdeaProjects\javaBasis\spring\target\classes\it\cast\circularDependency\C.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name ‘b’:
Requested bean is currently in creation: Is there an unresolvable circular reference?

Let’s take a look at an example of constructors with multiple @Autowired annotations:

@Component
public class A {
    
    
    private B b;
    private C c;
  
    @Autowired(required = false)
    public A(B b) {
    
    
        this.b = b;
    }
  
    @Autowired
    public A(B b, C c) {
    
    
        System.out.println("b=" + b + ", c=" + c);
        this.b = b;
        this.c = c;
    }
}
  
@Component
public class B {
    
    
  
}
  
@Component
public class C {
    
    
  
}

As mentioned above, if the attribute required of the @Autowired annotation is true, no other constructors are allowed to appear with the @Autowired annotation (the required of the @Autowired annotation defaults to true, so the above will report an error)

The error log is:

org.springframework.beans.factory.BeanCreationException:
Error creating bean with name ‘a’: Invalid autowire-marked constructors:
[public it.cast.circularDependency.A(it.cast.circularDependency.B)].
Found constructor with ‘required’ Autowired annotation:
public it.cast.circularDependency.A(it.cast.circularDependency.B,it.cast.circularDependency.C)

Use the following writing method to avoid errors. Spring supports multiple constructors with @Autowired annotations, but the required attributes must all be false.

@Component
public class A {
    
    
    private B b;
    private C c;
  
    @Autowired(required = false) 
    public A(B b) {
    
    
        this.b = b;
    }
  
    @Autowired(required = false)
    public A(B b, C c) {
    
    
        System.out.println("b=" + b + ", c=" + c);
        this.b = b;
        this.c = c;
    }
}
  
@Component
public class B {
    
    
  
}
  
@Component
public class C {
    
    
  
}

I won’t introduce much about the @Autowired annotation on the method. You will first get the parameter list of the method, and then find the corresponding bean in Spring IOC according to the injection rules mentioned above.

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/134961224