Spr2: introduction of IOC theory

Keywords: Java Spring unit testing ioc mvc

2.1 introduction

The following uses specific examples to introduce the idea of IOC. Firstly, the project follows the MVC development concept, mainly including dao layer, service layer and Test at the same level as main.

2.2 examples

2.2.1 code

UserDao interface:

package com.yun.dao;

public interface UserDao {
    public void speak();
}

UserDaoChineseImp implementation class:

package com.yun.dao;

public class UserDaoChineseImp implements UserDao{
    @Override
    public void speak() {
        System.out.println("I come from China. I speak Chinese");
    }
}

Tip: the speak() method is defined in the UserDao interface, and the details of this method are implemented in UserDaoChineseImp.

UserService interface:

package com.yun.service;

public interface UserService {
    public void speak();
}

UserServiceImp implementation class:

package com.yun.service;

import com.yun.dao.UserDaoChineseImp;
import com.yun.dao.UserDao;

public class UserServiceImp implements UserService{
    private UserDao userDao;

    public UserServiceImp(){
        userDao = new UserDaoChineseImp();
    }

    @Override
    public void speak() {
        userDao.speak();
    }
}

Tip: the speak() method is defined in the userservice interface. In the UserServiceImp implementation class, the private member attribute UserDao is defined and assigned in the parameterless construction method through upper transformation. It also rewrites the speak() method in the UserService interface and invokes the speak() method of UserDaoChineseImp in the method.

Test interface:

package com.yun;

import com.yun.service.UserService;
import com.yun.service.UserServiceImp;
import org.junit.Test;

public class MyTest {
    @Test
    public void speakTest(){
        UserService userService = new UserServiceImp();
        userService.speak();
    }
}

Thinking: when testing, you just need to instantiate the service layer and call the method. However, it is worth mentioning that if there are multiple implementation classes in the dao layer, such as Americans, Japanese, Russians, etc., how to call the dao layer in the service layer. As a beginner, I think there are two methods that can be adopted. First, create multiple implementation classes in the service layer to correspond to the dao layer one by one; Second, in the implementation class of the service layer, all implementation classes are defined as member variables and assigned values. These two methods are feasible to a certain extent. However, once the underlying implementation classes need to be added, due to the high coupling, most of the code needs to be changed, which can be said to lead the hair and affect the whole body. Therefore, IOC is particularly important, and the official method is to use setter() method for dynamic object injection.

2.2.2 IOC code change

UserDaoAmericanImp implementation class added in dao layer:

package com.yun.dao;

public class UserDaoAmericanImp implements UserDao{
    @Override
    public void speak() {
        System.out.println("I come from America. I speak English");
    }
}

service layer UserServiceImp:

package com.yun.service;

import com.yun.dao.UserDao;

public class UserServiceImp implements UserService{
    private UserDao userDao;

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

    @Override
    public void speak() {
        userDao.speak();
    }
}

Test interface:

package com.yun;

import com.yun.dao.UserDaoAmericanImp;
import com.yun.dao.UserDaoChineseImp;
import com.yun.service.UserService;
import com.yun.service.UserServiceImp;
import org.junit.Test;

public class MyTest {
    @Test
    public void speakTest(){
        UserService userService = new UserServiceImp();

        //Chinese test
        ((UserServiceImp)userService).setUserDao(new UserDaoChineseImp());
        userService.speak();

        //English test
        ((UserServiceImp)userService).setUserDao(new UserDaoAmericanImp());
        userService.speak();

    }
}

Summary: Here we will find that there is no major change in the service layer, but dynamic assignment through the setter() method. When we test, we only need to dynamically pass the object. However, it is worth noting that in the above code, type coercion must be performed when the object is dynamically passed in. Because userservice = new userserviceimp(); Statement, which can be said to use a subclass as a parent class (although this is an interface). And this kind of object is called the upper transformation object. The upper transformation object can only call methods that are not overridden by the parent class and methods that have been overridden by the child class. When we need to call the methods of the subclass itself, we need to cast the object to the subclass. This dynamic object injection is the idea of IOC, but it is more than that. In the former way, the program actively creates objects, while the latter passively receives objects. At this point, we can no longer focus on object management and reduce system coupling, but we can focus more on business development.

2.3 HelloSpring

Entity class:

package com.yun.pojo;

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="hello" class="com.yun.pojo.Hello">
        <property name="str" value="How do you do, Spring"/>
    </bean>

</beans>


Test:

package com.yun;

import com.yun.pojo.Hello;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello) applicationContext.getBean("hello");
        System.out.println(hello);
    }
}

Tip: the IOC idea is a major focus of Spring, and the current Hello Spring is created using Spring. At this time, we leave the creation, management and assembly of objects to Spring for operation. At this time, it is still the embodiment of IOC, but Spring does better than us and encapsulates the bottom layer.

Inversion: the program creates objects actively and accepts objects passively.

Control: specify who controls the creation of objects. In traditional programs, program objects are created by programs, while in Spring, objects are created by Spring.

Dependency injection: use setter() method to inject objects.

2.4 IOC object creation

2.4.1 object creation

On the basis of 2.3, add a World entity class, add an output statement in the nonparametric construction method of Hello class, and finally add the test method to the output statement of response.

World.java:

package com.yun.pojo;

public class World {

    public World(){
        System.out.println("This is world Entity class");
    }

    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "World{" +
                "str='" + str + '\'' +
                '}';
    }
}

Hello.java:

package com.yun.pojo;

public class Hello {

    public Hello(){
        System.out.println("This is Hello Entity class");
    }

    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

Test interface:

package com.yun;

import com.yun.pojo.Hello;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test(){
        System.out.println("for the first time");
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        System.out.println("The second time");
        Hello hello = (Hello) applicationContext.getBean("hello");
        System.out.println("third time");
        System.out.println(hello);
    }
}

Execution results:

for the first time
 This is Hello Entity class
 This is world Entity class
 The second time
 third time
Hello{str='How do you do, Spring'}

Process finished with exit code 0

Summary: as can be seen from the above results, when the program executes the new ClassPathXmlApplicationContext("beans.xml") statement, Spring will automatically instantiate the beans registered in the container Bean.xml. Therefore, when the appcationContext.getBean("hello") statement is executed, Spring will pass the instantiated object. Even if we create a new Hello hello1 = (Hello) applicationContext.getBean("hello") object and calculate hello with hello1 = = the result is still true. Moreover, by default, Spring instantiated objects use parameterless construction.

2.4.2 how spring creates objects

  • Nonparametric construction

    Spring default mode

  • Parameterized construction method: the parameterized construction method is defined in the entity class, and the implicit nonparametric construction method fails.

    • Use index to pass parameters:

      <bean id="hello2" class="com.yun.pojo.world">
              <constructor-arg index="0" value="Good noon"/>
              <constructor-arg index="1" value="7978"/>
          </bean>
      

      Tip: you must pass in as many parameters as there are in the parameter constructor. Of course, if the constructor is overloaded, the matching constructor will be automatically selected.

    • Use type to transfer parameters:

       <bean id="hello2" class="com.yun.pojo.world">
              <constructor-arg type="java.lang.String" value="Hello"/>
           <constructor-arg type="..." value="..."/>
          </bean>
      

      Tip: similarly, the constructor must have as many clauses as there are parameters. Unless the constructor is overloaded, an error will be reported.

    • Pass parameters by name:

       <bean id="hello2" class="com.yun.pojo.world">
             <constructor-arg name="str" value="This is name mode"/>
              <constructor-arg name="..." value="..."/>
          </bean>
      

      Tip: as above, parameters must be passed according to the constructor.

In the end, IOC's idea is not limited to these examples. It needs to deepen the impression in daily use and contact.

Posted by Altair on Wed, 08 Sep 2021 03:20:57 -0700