[Spring] Spring5——IOC简介(一)

目录

一、概念及原理

1、什么是 IOC

2、原理

二、IOC 操作——Bean 管理

1、什么是 Bean 管理

2、Bean 管理操作有两种方式

3、基于 xml 方式创建对象

三、xml 方式注入普通类型属性

1、使用 set 方法注入

2、使用有参构造函数注入

四、xml 方式注入其他类型属性

1、注入字面量

2、注入外部 Bean

3、注入内部 Bean 和级联赋值

五、xml 方式注入集合类型属性

1、注入数组、List 、Map、 Set 集合类型属性

2、在集合内设置对象类型

3、抽取公共属性值


一、概念及原理

1、什么是 IOC

(1)控制反转(Inversion of Control),把对象创建(new)和对象之间的调用(.function()),交给 Spring 管理;

(2)使用 IOC 的目的:降低耦合度;

(3)IOC 底层原理:xml 解析、工厂模式、反射

  • 反射:通过获取类的字节码文件(.class),来操作类方法

2、原理

Class 之间的调用形式决定了耦合度的高低,从原始方式工厂模式IOC,耦合度做到了越来越低。

(1)原始方式

假如我们现在要编写一个 Dao 和 Service,但是我们不懂任何设计模式,于是做出了在 Service 方法中 new Dao 的操作。如果 Dao 代码更变,那么 Service 也得跟着改变,耦合度较高

[Spring] Spring5——IOC简介(一)_第1张图片

(2)工厂模式

使用一个中间类,写一个 static 方法获取 Dao 对象,然后 Service 调用这个方法获取 Dao 对象,这样可以降低 Service 和 Dao 的耦合度。

虽然产生了 Factory 和 Dao 的耦合,但耦合程度比原始方式低。

[Spring] Spring5——IOC简介(一)_第2张图片

(3)IOC 容器底层

IOC 分两步,进一步降低耦合度,降低到最低限度,这样我们只需要修改配置文件即可。

  • 第一步:配置 xml 配置文件,配置创建的对象

  • 第二步:对应 Service 类和 Dao 类,创建工厂类

[Spring] Spring5——IOC简介(一)_第3张图片

(4)IOC 接口

(4-1)IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂;

(4-2)Spring 提供 IOC 容器实现两种方式(接口):

  • BeanFactory:IOC 容器基本实现方式(开发中不常用,是 Spring 内部实现用的);
  • ApplicationContext:BeanFactory 的子接口,提供更多更好的功能;

(4-3)特点:

  • BeanFactory 加载配置文件时不会创建对象,使用时才会创建;
  • ApplicationContext 加载配置文件时就会创建对象;

 (4-4)实现类:

  • FileSystemXmlApplicationContext:需要传入 xml 的盘符绝对路径;
  • ClassPathXmlApplicationContext:传入 xml 的 src 下的类路径;

二、IOC 操作——Bean 管理

1、什么是 Bean 管理

是指两种操作:创建对象、属性注入。

(1)Spring 创建对象;

  • xml 配置创建对象

(2)Spring 属性注入 

  • 对于一个类属性(private int num;),可以用 setNum(),当交给 Spring 操作,就是属性注入

2、Bean 管理操作有两种方式

(1)基于 xml 配置文件方式实现

(2)基于注解方式实现

3、基于 xml 方式创建对象

在 xml 中使用 bean 标签,添加对应属性,就可以实现创建对象。

(1)属性

  • id:表示给对象取一个别名(标识),在 getBean() 方法中传入对应字符串;
  • class:对象所在类的全路径;
  • name:作用与 id 属性一致,但是 id 不能有特殊字符,name 可以;

(2)创建对象时,默认执行无参构造方法

三、xml 方式注入普通类型属性

DI:依赖注入,就是注入属性。

在 Spring 中,支持两种注入方式:有参构造和 set 方法

1、使用 set 方法注入

(1)创建类,定义属性和对应的 set 方法

package com.demo.pojo;

public class Book {
    private Integer id;
    private String name;

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

(2)在 spring 配置文件配置对象创建,配置属性注入

标签中嵌套 标签:

  • name:属性名,要与类内的属性名一致;
  • value:属性值; 



    
        
        
    

(3)测试代码

这里是把 bean.xml 放到了 resources 文件夹下,并且标记为了源代码根目录。

import com.demo.pojo.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BookTest {
    @Test
    public void testCreate() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Book book = context.getBean(Book.class);
        System.out.println(book.getId() + "  " + book.getName());
    }
}

2、使用有参构造函数注入

有参构造注入与 set 方法注入的区别仅在于 标签内的子标签不同,即给属性注入值的标签不同

(1)创建类,定义属性,创建属性对应有参数构造方法

package com.demo.pojo;

public class Order {
    private String name;
    private String address;

    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }

    public Order(String name, String address) {
        this.name = name;
        this.address = address;
    }
}

(2)在 spring 配置文件中进行配置

写完 标签后会报错,因为没有无参构造,所以要添加 标签:

  • name:同类属性名;
  • value:属性值;
  • index:有参构造函数中的第 index 个参数,可以代替 name,但用 name 更直观;



    
        
        
    

(3)测试代码

import com.demo.pojo.Order;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class OrderTest {
    @Test
    public void testOrder() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Order order = context.getBean("order", Order.class);
        System.out.println(order.getName() + "  " + order.getAddress());
    }
}

四、xml 方式注入其他类型属性

1、注入字面量

字面量就是一些常量。比如 private String s = "123"。

(1)null 值

给 Book 类添加一个属性 price,并且将其设置为 null。




    
        
        
        
            
        
    

(2)属性值包含特殊符号

把 Book 类的 name 属性值,加上 << >>(不是书名号,是两个大于、小于)。可以考虑使用 xml 提供的 CDATA




    
        
        
            >]]>
        
        
            
        
    

2、注入外部 Bean

(1)创建两个类 Service 类和 Dao 类

(1-1)UserService 类:

package com.demo.service.impl;

import com.demo.dao.UserDao;
import com.demo.service.UserService;

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

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

    @Override
    public void func() {
        System.out.println("调用 UserService 的 func");
        userDao.func();
    }
}

(1-2)UserDao 类:

package com.demo.dao.impl;

import com.demo.dao.UserDao;

public class UserDaoImpl implements UserDao {
    @Override
    public void func() {
        System.out.println("调用 UserDao 的 func");
    }
}

(2)在 spring 配置文件中进行配置

为 userService 注入 userDao 对象:

  • name:类的属性名;
  • ref:创建 userDao 对象的 里的 id 的属性值,这就是注入外部 Bean 的体现;



    
        
    
    

    

(3)测试代码

import com.demo.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("Service-Dao-Bean.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.func();
    }
}

(4)输出结果

[Spring] Spring5——IOC简介(一)_第4张图片

3、注入内部 Bean 和级联赋值

数据库的表与表之间有一对一、一对多、多对一的关系,内部 Bean 和级联赋值就是处理这种数据的。其中主要关注一下级联赋值,因为内部 Bean 和外部 Bean 纯粹只是 xml 内的一点写法区别

下面用一对多关系,部门与员工(1:n),来做个例子。

(1)Department 类和 Empolyee 类:

package com.demo.pojo;

public class Department {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
package com.demo.pojo;

public class Employee {
    private String name;
    private String gender;
    // 一个员工属于某一个部门
    private Department department;

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

(2)Dep-Emp-Bean.xml:

标签中,嵌套一个 ,即为内部 Bean。




    
    
        
        
        
        
        
            
            
                
            
        
    

 其实我们发现,只要给对象类型的 加上 ref 属性值,再把 departmen 的 放到外面,就是一个外部 Bean

而这其实就是级联赋值第一种写法:




    
    
        
        
        
        
        
    
    
        
    



(3)测试代码:

import com.demo.pojo.Employee;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DepEmpTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("Dep-Emp-Bean.xml");
        Employee employee = context.getBean("employee", Employee.class);
        System.out.println(employee.getName() + "  "
                + employee.getGender() + "  "
                + employee.getDepartment().getName());
    }
}

(4)输出结果:

[Spring] Spring5——IOC简介(一)_第5张图片

(5)级联赋值的第二种写法

本质上就是先通过 ref 连接 department 对象,然后通过 getName() 方法获取 department 的 name 属性。(反射无处不在)




    
    
        
        
        
        
        
        
    
     
        
        
    

(6)输出结果

[Spring] Spring5——IOC简介(一)_第6张图片

五、xml 方式注入集合类型属性

1、注入数组、List 、Map、 Set 集合类型属性

(1)创建类,定义数组、list、map、set 类型属性,生成对应 set 方法

package com.demo.pojo;

import java.util.*;

public class Student {
    private String[] courses;
    private List list;
    private Map map;
    private Set set;

    public Set getSet() {
        return set;
    }

    public void setSet(Set set) {
        this.set = set;
    }

    public String[] getCourses() {
        return courses;
    }

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }
}

(2)在 spring 配置文件进行配置

对于每一种不同的集合,都有相对应的标签可以使用,在其对应的标签内添加 即可。




    
        
        
            
                Java编程
                Sql教学
            
        
        
        
            
                list01
                list02
            
        
        
        
            
                
                
            
        
        
        
            
                set01
                set02
            
        
    

(3)测试代码

import com.demo.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class SetBeanTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("SetBean.xml");
        Student student = context.getBean("student", Student.class);
        System.out.println(Arrays.toString(student.getCourses()));
        System.out.println(student.getList());
        System.out.println(student.getMap());
        System.out.println(student.getSet());
    }
}

(4)输出结果

[Spring] Spring5——IOC简介(一)_第7张图片

2、在集合内设置对象类型

集合内保存的一般都是某些自定义的对象类型,所以需要知道如何注入对象到集合类型。

(1)Teacher 类和 Course 类

package com.demo.pojo;

import java.util.List;

public class Teacher {
    private List courseList;

    public List getCourseList() {
        return courseList;
    }

    public void setCourseList(List courseList) {
        this.courseList = courseList;
    }

}
package com.demo.pojo;

public class Course {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

(2)SetObjectBean.xml

使用 的 bean 属性来链接外部 Bean,实现将对象类型属性值注入到 List(Map、Set、……)集合。




    
        
            
                
                
            
        
    

    
    
        
    
    
        
    

(3)测试代码

import com.demo.pojo.Teacher;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SetObjectBeanTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("SetObjectBean.xml");
        Teacher teacher = context.getBean("teacher", Teacher.class);

        System.out.println(teacher.getCourseList());
    }
}

(4)输出结果

[Spring] Spring5——IOC简介(一)_第8张图片

3、抽取公共属性值

(1)在 spring 配置文件中引入名称空间 util

先添加名称空间,然后把 xsi 的值复制一份,紧接着后面粘贴上,把复制来的 beans 都改成 util。

[Spring] Spring5——IOC简介(一)_第9张图片

(2)使用 util 标签完成 list 集合注入提取

其他类型的集合,输入 util: 会有提示。




    
     
        
        Java
        C++
        Python
    

    
        
    

(3)ProgramLanguage 类:

package com.demo.pojo;

import java.util.List;

public class ProgramLanguage {
    private List list;

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }
}

(4)测试代码

import com.demo.pojo.ProgramLanguage;
import com.demo.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class commonTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("common.xml");
        ProgramLanguage programLanguage = context.getBean("list", ProgramLanguage.class);

        System.out.println(programLanguage.getList());
    }

}

(5)输出结果

[Spring] Spring5——IOC简介(一)_第10张图片

 

你可能感兴趣的:(Spring,spring,java,后端)