[spring]spring_IOC and DI

Spring overview

Spring is a lightweight open source framework for layered Java SE/EE application full stack, with IOC (Inverse Of Control) and AOP (Aspect Oriented Programming) as the kernel.

It provides many enterprise application technologies such as presentation layer spring MVC, persistence layer spring JDBC template and business layer transaction management. In short, it simplifies java development. It can also integrate many famous third-party frameworks and class libraries in the world, and gradually become the most used open source framework for Java EE enterprise applications.

Here we need to understand several basic concepts

  • Inversion of control: it is not a technology, but a design idea to reduce the coupling relationship between objects. In Java development, Ioc means giving objects to container control

    The most common method is called Dependency Injection (DI) and the other is called Dependency Lookup

    Dependency injection: it means that the container is responsible for creating and maintaining dependencies between objects, rather than creating and solving its own dependencies through the object itself. Objects of other classes need to be used in the current class, which are provided by Spring (that is, new is omitted). We only need to explain it in the configuration.

  • Aspect oriented programming: my understanding: extract the same code. For example, all content in the background needs to be logged in. The method to judge whether to log in is aspect oriented programming

    • Function: during the running of the program, enhance the function of the method without modifying the source code.

Spring quick start

Origin of ioc and dependency injection

We know that in the object-oriented design software system, its bottom layer is composed of N objects. Each object cooperates with each other to finally realize the systematic business logic. For example, a pocket watch has multiple independent gears, which mesh with each other and work together to complete a task. We can see that in such a gear set, if there is a problem with one gear, it may affect the normal operation of the whole gear set. This is the very close coupling relationship. Therefore, in order to solve this problem, software expert Michael Mattson proposed IOC theory in 1996 to realize the "decoupling" between objects. At present, this theory has been successfully applied to practice.

IOC is the abbreviation of Inversion of Control, and most books translate it into "control inversion". The view of IOC theory is generally as follows: decoupling between dependent objects with the help of "third party". As shown below:

As you can see, due to the introduction of the "third party" in the middle, that is, the IOC container, there is no coupling relationship between the four objects A, B, C and D. the transmission between gears all depends on the "third party", and the control of all objects is handed over to the "third party" IOC container. Therefore, the IOC container has become the key core of the whole system, It plays A role similar to "adhesive" and binds all objects in the system together. Without this "adhesive", objects will lose contact with each other. This is the reason why some people compare IOC container to "adhesive".

Let's do another experiment: remove the IOC container in the middle of the figure above, and then take a look at the system:

The picture we see now is all that we need to complete to realize the whole system. At this time, the four objects A, B, C and d have no coupling relationship and no connection with each other. In this way, when you implement A, you don't need to consider B, C and D at all, and the dependency between objects has been reduced to the minimum. Therefore, if the IOC container can be implemented, it will be A wonderful thing for system development. Each member participating in the development only needs to implement his own class, which has nothing to do with others!

Let's take a look at why the inversion of control (IOC) has such a name? Let's compare:

  • Before the software system introduces the IOC container, as shown in Figure 1, object A depends on object B. when object A initializes or runs to A certain point, it must actively create object B or use the created object B. Whether you create or use object B, control is in your own hands.

  • This situation is completely changed after the software system introduces the IOC container. As shown in Figure 3, due to the addition of the IOC container, the direct connection between object A and object B is lost. Therefore, when object A runs to the point where object B is needed, the IOC container will actively create an object B and inject it into the place where object A needs.

Through the comparison before and after, it is not difficult to see that the process of object A obtaining dependent object B changes from active behavior to passive behavior, and the control right is reversed. This is the origin of the name "control reversal".

In 2004, Martin Fowler discussed the same question. Since IOC is control reversal, what aspects of control have been reversed? After detailed analysis and demonstration, he came to the answer: "the process of obtaining dependent objects has been reversed". After the control is reversed, the process of obtaining dependent objects is changed from self-management to active injection by IOC container. Therefore, he gave "inversion of control" a more appropriate name called "Dependency Injection". His answer actually gives a way to implement IOC: injection. The so-called Dependency Injection means that the IOC container dynamically injects certain dependencies into objects during operation.

Therefore, dependency injection (DI) and inversion of control (IOC) describe the same thing from different angles, that is, decoupling between objects by introducing IOC container and using dependency injection.

Advantages of Spring

1) Convenient decoupling and simplified development

Through the IOC container provided by Spring, the dependencies between objects can be controlled by Spring to avoid excessive coupling caused by hard coding.

Users do not have to write code for the very low-level requirements such as singleton pattern class and attribute file parsing, and can focus more on the upper-level applications.

2) AOP programming support

Through the AOP function of Spring, it is convenient for aspect oriented programming. Many functions that are not easy to be realized with traditional OOP can be easily realized through AOP.

3) Declarative transaction support

It can free us from the monotonous and boring transaction management code, and carry out transaction management flexibly in a declarative way, so as to improve the development efficiency and quality

4) Facilitate program testing

Almost all testing work can be carried out in a container independent programming way. Testing is no longer an expensive operation, but a thing to do at will.

Spring architecture

Spring configuration file = > IOC container

Bean tag basic configuration

Function: assign the creation of objects to the Spring container for management through configuration.

By default, it calls the parameterless constructor in the class. If there is no parameterless constructor, it cannot be created successfully.

Related properties

  • id: the unique identifier of the Bean instance in the Spring container;
  • class: the fully qualified name of the Bean.

Bean tag range configuration

Scope refers to the scope of the object. The values are as follows:

Value range explain
singleton Default, singleton
prototype Multiple cases
request In the WEB project, Spring creates a Bean object and stores the object in the request field
session In the WEB project, Spring creates a Bean object and stores the object in the session domain
global session In the WEB project, the application is in the Portlet environment. If there is no Portlet environment, the global session is equivalent to the session

When the value of scope is singleton

  • Number of instantiations of Bean: 1
  • Bean instantiation timing: instantiate the configured bean instance when the Spring core file is loaded
  • Bean lifecycle:
    • Object creation: when the application loads and creates a container, the object is created;
    • Object running: as long as the container is, the object will always be alive;
    • Object destruction: when the application unloads and destroys the container, the object is destroyed.

When the value of scope is prototype

  • Number of Bean instantiations: multiple
  • Instantiation timing of Bean: instantiate Bean when calling getBean() method
  • Bean lifecycle:
    • Object creation: create a new object instance when using an object;
    • Object running: as long as the object is in use, it will always be alive;
    • Object destruction: when an object is not used for a long time, it is recycled by the Java garbage collector.

bean lifecycle configuration

Init method: Specifies the name of the initialization method in the class

Destroy method: Specifies the name of the destroy method in the class

There are three ways to instantiate bean s

Spring quick start

Instantiate using the parameterless construction method

Create a class object according to the default parameterless constructor. If there is no default parameterless constructor in the bean, the creation will fail.

<bean id="userDao" class="com.qfedu.dao.impl.UserDaoImpl">

Factory static method instantiation

Create static factory

public class StaticBeanFactory {
    public static UserDao getUserDaoImpl() {
        return new UserDaoImpl();
    }
}

Configure in the Spring configuration file

<!-- Static factory initialization -->
<bean id="userDao" class="com.qfedu.factory.StaticBeanFactory" factory-method="getUserDaoImpl"></bean>

test

//Demonstrates how to create a Bean through a static factory
@Test
public void test1() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDao userDao = (UserDao) context.getBean("userDao");
    userDao.save();
}

Factory instance method instantiation

Create dynamic factory

public class DynamicBeanFactory {
    public UserDao getUserDao() {
        return new UserDaoImpl();
    }
}

Configure in the Spring configuration file

<bean id="factory" class="com.qfedu.factory.DynamicBeanFactory"></bean>
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>

The test is the same as above

DI (dependency injection)

Dependency Injection: Dependency Injection means that the container is responsible for creating and maintaining dependencies between objects, rather than creating and solving its own dependencies through the object itself. Objects of other classes need to be used in the current class, which is provided by Spring. We only need to explain it in the configuration.

The dependencies between the business layer and the persistence layer are maintained by Spring after using Spring.

Simply put, it means waiting for the framework to transfer the persistence layer object to the business layer without getting it ourselves.

That is, the private UserDao userDao = new object () in the service becomes private UserDao userDao;, Omit new

Construction method injection

  1. Create interface UserService and implementation class UserServiceImpl
public interface UserService {
    void save();
}

public class UserServiceImpl implements UserService {
    //There must be this attribute here. Our ultimate goal is to associate this attribute with a UserDaoImpl object
    private UserDao userDao;

    public UserServiceImpl() {
    }
    
    //There must be a parameterized construction method to complete dependency injection
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
}
  1. Configure in the Spring configuration file
<bean id="userDao" class="com.qfedu.dao.impl.UserDaoImpl"></bean>

<bean id="userService" class="com.qfedu.service.impl.UserServiceImpl">
    <!-- Construction method injection, through ref take id For“ userDao"of bean Passed on to UserServiceImpl Of construction method userDao Formal parameter -->
    <constructor-arg name="userDao" ref="userDao" />
</bean>
  1. test
@Test
public void test3() {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    UserService userService = (UserService)context.getBean("userService");
    userService.save();
}

set method injection (key)

Add the set method in UserServiceImpl

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

Configure in the Spring configuration file

<bean id="userService" class="UserServiceImpl">
    <!-- set Method injection -->
    <property name="userDao" ref="userDao"></property>
</bean>

The test method is the same as above

p namespace injection

The essence of p namespace injection is also set method injection, but it is more convenient than the above set method injection, which is mainly reflected in the configuration file

Introduce P namespace

xmlns:p="http://www.springframework.org/schema/p"

Configure in the Spring configuration file

<!-- p Namespace injection -->
<bean id="userService" class="com.qfedu.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>

Dependency injection other types

In the above case, we learned how to inject data of reference type. In addition to reference data type, common data type and collection data type, we can also inject data.

Common data type injection

Create Department entity class

//Entity class representing Department
public class Department {
    private Integer id;//Department number
    private String name;//Department name
    private String desc;//Department description
    
    //set and get methods
    //toString method
}
  1. Configure in the Spring configuration file
<!--
    adopt Spring of IOC Container creation Department Class and inject values into its properties
    Parameterless construction method instantiation
-->
<bean id="department" class="com.qfedu.entity.Department">
    <!-- set Method injection
        value: Simple type
    -->
    <property name="id" value="1" />
    <property name="name" value="R & D department" />
    <property name="desc" value="Project R & D" />
</bean>

test

@Test
public void test6() {
    //Parsing the configuration file -- creating objects -- the objects are handed over to Spring's IOC container for management
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //Gets the object of the Department
    Department department = (Department)context.getBean("department");
    //Print object
    System.out.println(department);
}

Reference type injection

  1. Create entity class Department
//Entity class representing Department
public class Department {
    private Integer id;//Department number
    private String name;//Department name
    private String desc;//Department description
    private Address address;//Department address
    
    //set,get
    //toString
}

Configure in the Spring configuration file

<bean id="address" class="com.qfedu.entity.Address">
    <property name="province" value="Shandong Province" />
    <property name="city" value="Qingdao" />
    <property name="county" value="Shibei District" />
    <property name="street" value="Longcheng Road" />
    <property name="no" value="31 number" />
</bean>

<!--
    adopt Spring of IOC Container creation Department Class and inject values into its properties
    Parameterless construction method instantiation
-->
<bean id="department" class="com.qfedu.entity.Department">
    <!-- set Method injection
        value: Simple type
    -->
    <property name="id" value="1" />
    <property name="name" value="R & D department" />
    <property name="desc" value="Project R & D" />
    <!-- set Method injection
        ref: reference type
    -->
    <property name="address" ref="address" />
</bean>

The test is the same as above

Injection of set data type (list < string >)

Create Employee entity class

//Represents the entity class of the employee
public class Employee {
    private Integer id;//Employee number
    private String name;//full name
    private Integer age;//Age
    private String gender;//Gender
    private List<String> hobby;//hobby
        
    //set and get methods
    //toString method
}
  1. Configure in the Spring configuration file
<!--
    adopt Spring of IOC Container creation Employee Class and inject values into its properties
    Parameterless construction method instantiation
-->
<bean id="e1" class="com.qfedu.entity.Employee">
    <property name="id" value="1" />
    <property name="name" value="zs" />
    <property name="age" value="30" />
    <property name="gender" value="male" />
    <!--        Collection type injection    -->
    <property name="hobby">
        <list>
            <value>Learning 1</value>
            <value>Learning 2</value>
            <value>Learning 3</value>
        </list>
    </property>
</bean>

The test is the same as above

Injection of collection data type (list < Object >)

  1. Modify Department entity class
//Entity class representing Department
public class Department {
    private Integer id;//Department number
    private String name;//Department name
    private String desc;//Department description
    private Address address;//Department address
    private List<Employee> emps;//Ordinary staff
    
    //set and get methods
    //toString method
}
  1. Configure in the Spring configuration file
<bean id="e1" class="com.qfedu.entity.Employee">
    <property name="id" value="1" />   <property name="name" value="zs" />    <property name="age" value="30" />    <property name="gender" value="male" />
    <!--  Collection type injection         -->
    <property name="hobby">        <list>            <value>Learning 1</value>            <value>Learning 2</value>            <value>Learning 3</value>        </list>    </property>
</bean>

<bean id="e2" class="com.qfedu.entity.Employee">
    <property name="id" value="1" />    <property name="name" value="ls" />    <property name="age" value="31" />    <property name="gender" value="male" />
    <!--Collection type injection -->
    <property name="hobby">        <list>            <value>Mountain climbing</value>            <value>Swimming</value>            <value>Online games</value>        </list>    </property>
</bean>

<bean id="department" class="com.qfedu.entity.Department">
    <!-- set Method injection
            value: Simple type
        -->
    <property name="id" value="1" />
    <property name="name" value="R & D department" />
    <property name="desc" value="Project R & D" />
    <!-- set Method injection
            ref: reference type
         -->
    <property name="address" ref="address" />
    <property name="emps">
        <list>
            <ref bean="e1" />
            <ref bean="e2" />
        </list>
    </property>
</bean>

The test is the same as above

Injection of collection data type (map < string >)

  1. Modify Department and add properties
//Entity class representing Department
public class Department {
    private Integer id;//Department number
    private Map<String, Employee> leader;//Department head
    //set,get
    //toString
}
  1. Configure in the Spring configuration file
<bean id="e1" class="com.qfedu.entity.Employee">
    <property name="id" value="1" />
</bean>

<bean id="e2" class="com.qfedu.entity.Employee">
    <property name="id" value="2" />
</bean>


<bean id="department" class="com.qfedu.entity.Department">
    <property name="id" value="1" />
    <property name="leader">
        <map>
            <entry key="CEO" value-ref="e1" />
            <entry key="CTO" value-ref="e2" />
        </map>
    </property>
</bean>

The test is the same as above

Injection of collection data types (properties)

Create the entity class JdbcConfig and add Properties

package com.qfedu.entity;

import java.util.Properties;

public class JdbcConfig {
    private Properties config;

    public Properties getConfig() {
        return config;
    }

    public void setConfig(Properties config) {
        this.config = config;
    }

    @Override
    public String toString() {
        return "JdbcConfig{" +
                "config=" + config +
                '}';
    }
}

Configure in the Spring configuration file

<bean id="jdbcConfig" class="com.qfedu.entity.JdbcConfig">
    <!-- Properties Type injection -->
    <property name="config">
        <props>
            <prop key="driverName">com.mysql.jdbc.Driver</prop>
            <prop key="url">jdbc:mysql://localhost:3306/test</prop>
            <prop key="username">root</prop>
            <prop key="password">root</prop>
        </props>
    </property>
</bean>

test

@Test
public void test8() {
    //Parsing the configuration file -- creating objects -- the objects are handed over to Spring's IOC container for management
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //Get the object of Employee
    JdbcConfig config = (JdbcConfig)context.getBean("jdbcConfig");
    //Print object
    System.out.println(config);
}

Import other profiles

In actual development, there are many Spring configurations, which leads to the complexity and volume of Spring configuration. Therefore, some configurations can be disassembled into other configuration files, and loaded in the main Spring configuration file through the import tag.

<import resource="applicationContext-xxx.xml"/>

Tags: Java framework

Posted on Mon, 01 Nov 2021 08:50:57 -0400 by cookspyder