Spring: The way of dependency injection (setter injection, constructor injection, automatic assembly, collection injection)

Dependency injection methods include setter injection, constructor injection, automatic assembly, collection injection

First, the Maven project pom.xml depends on the package as follows:
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.22.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
    </dependencies>
</project>

[Note]: Except for the spring dependency package, the other three dependency packages mentioned above are used for testing.

1. Setter injection

Let me explain first, the files here are Book2Dao (interface), Book2DaoImpl (Book2Dao interface implementation class), Book2Service (interface), Book2ServiceImpl (Book2Service can implement class), Test2 (for testing). The example uses the save method of Book2Dao in the Book2ServiceImpl class, as follows:

Book2Dao

package com.bh.dao;
public interface Book2Dao {<!-- -->
    void save();
}

Book2DaoImpl

package com.bh.dao.Impl;

import com.bh.dao.Book2Dao;
public class Book2DaoImpl implements Book2Dao {<!-- -->
    public void save() {<!-- -->
        System.out.println("Book2DaoImpl has saved data!");
    }
}

Book2Service

package com.bh.service;

public interface Book2Service {<!-- -->
    void save();
}

Book2ServiceImpl

package com.bh.service.Impl;

import com.bh.dao.Book2Dao;
import com.bh.service.Book2Service;

public class Book2ServiceImpl implements Book2Service {<!-- -->
    private Book2Dao book2Dao;
    public void setBook2Dao(Book2Dao book2Dao) {<!-- -->
        this.book2Dao = book2Dao;
    }
    public void save() {<!-- -->
        book2Dao. save();
    }
}

applicationContext.xml configuration file

<?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

">

<!-- Open the context namespace -->
     <bean id="book2Dao" class="com.bh.dao.Impl.Book2DaoImpl"/>

    <bean id="book2Service" class="com.bh.service.Impl.Book2ServiceImpl">
        <property name="book2Dao" ref="book2Dao"/>
    </bean>
</beans>

[Note]: This xml file opens the context namespace for subsequent operations.
Test2

package com.bh;

import com.bh.service.Book2Service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {<!-- -->
    public static void main(String[] args) {<!-- -->
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Book2Service book2Service = ctx.getBean("book2Service", Book2Service.class);
        book2Service. save();
    }
}

The result of the operation is:
Please add a picture description

In this way, if multiple dependencies of other classes are introduced into the Book2ServiceImpl class, the corresponding property tags need to be written on the configuration file applicationContext.xml, and once Java The names of these imported dependent variables on the class are modified, and the property tags in the bean tags of the corresponding configuration files also need to be modified accordingly, which seems very cumbersome. Is there an easy way? Yes, that is to use automatic assembly.
Autowiring

Just modify the applicationContext.xml configuration file.

applicationContext.xml

<?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

">
<!-- Open the context namespace -->
     <bean id="book2Dao" class="com.bh.dao.Impl.Book2DaoImpl"/>

    <bean id="book2Service" class="com.bh.service.Impl.Book2ServiceImpl" autowire="byType"/>
</beans>

The result is the same as above.
If two beans of the same type Book2DaoImpl are defined in the above applicationContext.xml, an error will be reported as follows:
Please add a picture description

operation result:
Please add a picture description
Please add a picture description
From the analysis of the error message, it is because I have defined two beans of the same class type, and the automatic assembly method used is to assemble by type (byType), I can modify the automatic assembly type, use byName by name, so there is no problem, as follows:
Please add a picture description
After this modification, the result can be run normally. However, using assembly by name requires the id value of the bean. id value needs to be consistent with the corresponding variable name on the Java class, otherwise problems will occur.

For autowiring, the summary is as follows:

  • Autowiring is used for reference type dependency injection and cannot operate on simple types;
  • When using assembly by type, the bean of the same class in the container must be guaranteed to be unique, which is recommended;
  • When using assembly by name, you must ensure that the bean with the specified name in the container is not recommended because the variable name is coupled with the configuration;
  • The priority of automatic assembly is lower than that of setter injection and constructor injection, and automatic assembly fails when it occurs at the same time.

2. Constructor injection

Use the construction method to inject, the original Book2ServiceImpl class is modified to:
Book2ServiceImpl

package com.bh.service.Impl;

import com.bh.dao.Book2Dao;
import com.bh.service.Book2Service;

public class Book2ServiceImpl implements Book2Service {<!-- -->
    private Book2Dao book2Dao;
    public Book2ServiceImpl(Book2Dao book2Dao) {<!-- -->
        this.book2Dao = book2Dao;
    }

    public void save() {<!-- -->
        book2Dao. save();
    }
}

The above applicationContext.xml configuration file is modified as follows:

The operation result is the same as the above normal operation result;
If there is a simple type in the constructor, the constructor-arg tag is as follows:

<constructor-arg name="name" value="liuze"/>

However, once the name of the Java class variable is modified in this way, the configuration file also needs to be modified accordingly. The name attribute can be removed and replaced by index. The index value starts from 0, indicating the position of the formal parameter in the Java class construction method.
Please add a picture description

3. Collection injection

For example, there are some collection type variables in a Java class, such as array, List, Set, Map, Properties, the reference example is as follows (using setter injection):
RandomObject

package com.bh.other;

import java.util.*;

public class RandomObject {<!-- -->

    private int[] arrObj;
    private List<String> listObj;
    private Set<String> setObj;
    private Map<String,String > mapObj;
    private Properties propertiesObj;

    public void setArrObj(int[] arrObj) {<!-- -->
        this.arrObj = arrObj;
    }

    public void setListObj(List<String> listObj) {<!-- -->
        this.listObj = listObj;
    }

    public void setSetObj(Set<String> setObj) {<!-- -->
        this.setObj = setObj;
    }

    public void setMapObj(Map<String, String> mapObj) {<!-- -->
        this. mapObj = mapObj;
    }

    public void setPropertiesObj(Properties propertiesObj) {<!-- -->
        this.propertiesObj = propertiesObj;
    }

    public void save(){<!-- -->

        System.out.println("Save data...");
        System.out.println(Arrays.toString(arrObj));
        System.out.println(listObj);
        System.out.println(setObj);
        System.out.println(mapObj);
        System.out.println(propertiesObj);
    }
}

The applicationContext.xml configuration file is:

<bean id="randomObject" class="com.bh.other.RandomObject">
    <property name="arrObj">
         <array>
             <value>123</value>
             <value>456</value>
             <value>789</value>
         </array>
     </property>
     <property name="listObj">
         <list>
             <value>abc</value>
             <value>efg</value>
             <value>hij</value>
         </list>
     </property>
     <property name="setObj">
         <set>
             <value>abc</value>
             <value>efg</value>
             <value>hij</value>
             <value>abc</value>
         </set>
     </property>
     <property name="mapObj">
         <map>
             <entry key="name" value="liuze"/>
             <entry key="age" value="22"/>
             <entry key="address" value="hunan"/>
         </map>
     </property>
     <property name="propertiesObj">
         <props>
             <prop key="name">liuze</prop>
             <prop key="age">23</prop>
             <prop key="address">hunan</prop>
         </props>
     </property>
 </bean>

operation result:
Please add a picture description

How to use the above knowledge to inject data source objects?
applicationContext.xml

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc::mysql://localhost:3306/d_test"/>
    <property name="user" value="root"/>
    <property name="password" value="sxx123"/>
</bean>

You can still use the setter injection method, so how to load the custom properties file? This is the aplicationContext.xml file mentioned at the beginning. Did you find that there are a few more incomprehensible links at the beginning of this file than the default ones, which are used to open the context namespace.
Now there is a jdbc.properties file in the resources folder as follows:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc::mysql://localhost:3306/d_test
jdbc.username=root
jdbc.password=sxx123

How to read these data in aplicationContext.xml, as follows:
Please add a picture description
operation result:
Please add a picture description