[Spring] several methods of dependency injection

Posted by OU_Student on Fri, 21 Jan 2022 13:38:17 +0100

In the last article, I focused on the concepts of control inversion and dependency injection in Spring. What are the ways of dependency injection? What are their advantages and disadvantages? I will explain them in detail in this chapter.

Spring dependency injection can be divided into attribute injection and object injection according to object type injection. According to the injection methods, it can be divided into xml configuration file injection and annotation injection. There are three injection methods for xml:

  1. Construction method injection;
  2. setter method injection;
  3. p namespace injection.

Note: the P namespace is injected by a special setter method. Therefore, some people say that there are two injection methods for xml. This article will explain them separately for the sake of detailed introduction.

There are three annotation injection methods:

  1. Construction method injection;
  2. setter method injection;
  3. Automatic injection.

1, Object injection

1.1. xml file injection

1.1.1 construction method

public class A {

    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }

    public A(B b, String name) {
        this.b = b;
        this.name = name;
    }
}
public class B {

    private String name;

    private Double age;

    public B(String name, Double age) {
        this.name = name;
        this.age = age;
    }

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }
}
    <!--establish B of Bean object-->
    <!--
        constructor-arg:Constructor assignment,
        Note: you need to provide a constructor with parameters
        There are the following values:
            name: The parameter name required by the constructor
            value: Value corresponding to parameter name
            ref: Parameter is other bean
            type:Specifies the data type of the parameter in the constructor
            index:Specifies the index position of the parameter in the constructor -->
    <bean id="b" class="com.sxx.service.entity.B">
        <constructor-arg name="name" value="Zhang San"/>
        <constructor-arg name="age" value="12.58"/>
    </bean>

    <bean name="a" class="com.sxx.service.entity.A">
        <constructor-arg name="b" ref="b"/>
        <constructor-arg name="name" value="Wang Wu"/>
    </bean>
public class IocTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        A a = (A) applicationContext.getBean("a");
        a.a();
    }
}

Method B in B is executed, name = Zhang San, age=12.58
Method a in a is executed, name = Wang Wu

1.1.2 set method injection

public class A {

    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }
}
public class B {

    private String name;

    private String age;

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }
}
    <!--establish B of Bean object-->
     <!--
        property:The assignment attribute has the following values:
            name: Class, actually looking for set Method, such as setName -> name Can be assigned here, no set The method will report an error;
            value: Assign values to attributes, basic data and String Type of use this method;
            ref: Attribute assignment is other bean Type
    -->
    <bean id="b" class="com.sxx.service.entity.B">
        <property name="name" value="Zhang San"/>
        <property name="age" value="12"/>
    </bean>
     <bean name="a" class="com.sxx.service.entity.A">
        <property name="name" value="Li Si"/>
        <!--ref It points up id="b"-->
        <property name="b" ref="b"/>
    </bean>
public class IocTest {
    public static void main(String[] args) {
       ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        A a = (A) applicationContext.getBean("a");
        a.a();
        B b = (B) applicationContext.getBean("b");
        b.b();
    }
}

The results are as follows:

Method B in B is executed, name = Zhang San, age=12.58
Method a in a is executed, name = Li Si
Method B in B is executed, name = Zhang San, age=12.58

1.1.3. P namespace injection

public class A {

    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }
}
public class B {

    private String name;

    private Double age;

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="a" class="com.sxx.service.entity.A"
            p:name="Li Si" p:b-ref="b">
    </bean>
    <bean id="b" class="com.sxx.service.entity.B">
        <property name="name" value="Zhang San"/>
        <property name="age" value="12.58"/>
    </bean>

</beans>
public class IocTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        A a = (A) applicationContext.getBean("a");
        a.a();
    }
}

Method B in B is executed, name = Zhang San, age=12.58
Method a in a is executed, name = Li Si

1.2 annotation injection

1.2.1 construction method

public class A {

    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }

    public A(B b, String name) {
        this.b = b;
        this.name = name;
    }
}
public class B {

    private String name;

    private Double age;

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }

    public B(String name, Double age) {
        this.name = name;
        this.age = age;
    }
}
@Configuration
public class BeanConfig {
    @Bean("b")//Specify name=b instead of the default B
    public B B(){
       return new B("Zhang San", 12.4D);
    }
    @Bean
    public A a(){
       return new A(B(), "Li Si");
    }
}
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--add to spring Scan, range is com.sxx Remove all packages and their sub packages-->
    <context:component-scan base-package="com.sxx"/>
</beans>
public class IocTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        A a = (A) applicationContext.getBean("a");
        a.a();
    }
}

Method B in B is executed, name = Zhang San, age=12.4
Method a in a is executed, name = Li Si

1.2.2. setter method injection

public class A {

    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }
}
public class B {

    private String name;

    private Double age;

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }
}
<!--add to spring Scan, range is com.sxx Remove all packages and their sub packages-->
<context:component-scan base-package="com.sxx"/>
@Configuration
public class BeanConfig 
    @Bean
    //If A's key in the Ioc container is not specified, it defaults to the method name
    public B b(){
        B b = new B();
        b.setName("Zhang San");
        b.setAge(20D);
        return b;
    }
    @Bean
    //If A's key in the Ioc container is not specified, it defaults to the method name
    public A a(){
        A a = new A();
        //The above b() method is introduced
        a.setB(b());
        a.setName("Li Si");
        return a;
    }
}
public class IocTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        A a = (A) applicationContext.getBean("a");
        a.a();
    }
}

Method B in B is executed, name = Zhang San, age=20.0
Method a in a is executed, name = Li Si

1.2.3 automatic injection

The most representative of automatic injection are @ Resource and @ Autowired annotations. When there is only a single object in the container, the functions of the two annotations are the same and can be replaced with each other without affecting the use.

However, if there are multiple objects, @ Autowired only injects according to the type and will not match the name. If the injected object cannot be identified by type, it needs to be modified with @ Qualifier or @ Primary annotation.

@ Resource is jdk1 6. The supported annotations are assembled by name by default, and the name can be specified through the name attribute. If the name attribute is not specified, when the annotation is written on the field, the field name is taken by default and searched by name. If the annotation is written on the setter method, the default property name is used for assembly. Assemble by type when no bean matching the name is found. However, it should be noted that once the name attribute is specified, it will only be assembled by name.

1.3 another form of annotation injection

The annotation injection method we listed above is to implement dependency injection in the configuration file BeanConfig. There is another way to directly use @ Resource or @ Autowired in the class file.

1.3.1 construction method

@Component
public class A {

    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }

    @Autowired
    public A(B b) {
        this.b = b;
    }
}
@Component
public class B {

    private String name;

    private Double age;

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }
}
 <!--add to spring Scan, range is com.sxx Remove all packages and their sub packages-->
 <context:component-scan base-package="com.sxx"/>
public class IocTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("bean.xml");
        A a = (A) applicationContext.getBean("a");
        a.a();
    }
}

Method B in B is executed, name=null,age=null
Method a in a is executed, name=null

1.3.2. setter method injection

@Component
public class A {
    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }

    @Autowired
    public void setB(B b) {
        this.b = b;
    }
}

Refer to 1.3.1 for other methods and results

1.3.3 direct injection

@Component
public class A {
    @Autowired
    private B b;

    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }
}

Refer to 1.3.1 for other methods and results

2, Parameter injection

Parameter injection is mainly through @ Value injection

@Component
public class A {
    @Autowired
    private B b;

    @Value("Li Si")
    private String name;

    public void a(){
        b.b();
        System.out.println("A in a Method executed, name=" + name);
    }
}
@Component
public class B {

    @Value("Zhang San")
    private String name;

    @Value("20.4")
    private Double age;

    public void b(){
        System.out.println("B in b Method executed, name=" + name + ",age=" + age);
    }
}

Other configurations can refer to other dependency injection methods

The result is:

Method B in B is executed, name = Zhang San, age=20.4
Method a in a is executed, name = Li Si

Note: @ Value can not only configure its own properties, but also obtain the corresponding properties from the configuration file or configuration center

3, Comparison of advantages and disadvantages of several dependency injection

3.1. Constructor injection

Advantages: Based on constructor injection, the order of dependency injection will be fixed, and circular dependencies between bean objects we create are not allowed. In this way, Spring can solve the problem of circular dependencies.

Disadvantages: the disadvantage of using constructor injection is that when we need to inject more objects, our constructor will appear redundant, unsightly, poor readability and difficult to maintain.

3.2. setter based method injection

Advantages: Based on setter injection, dependency is injected only when the object needs to be injected, rather than during initialization.

Disadvantages: when we choose setter method to inject, we cannot set the object to final;

3.3. Based on automatic injection

Advantages: write comments on member variables to inject. This method is short, readable, does not need redundant code, and is convenient for maintenance.

Disadvantages:

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

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

                3. Class is highly coupled with DI container, so we can't use it externally;

                4. Class cannot be instantiated without reflection (for example, in unit test). You need to instantiate it with DI container, which is more like integration test;

Topics: Java Spring Back-end