[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 也得跟着改变,耦合度较高

(2)工厂模式

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

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

(3)IOC 容器底层

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

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

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

在之后的使用中,有一个 getBean 方法,底层就是通过工厂类的 getDao() 这类 get 方法实现的。 (工厂类的 get 方法和 id 值对应)

(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 配置文件配置对象创建,配置属性注入

在 <bean> 标签中嵌套 <property name="" value=""> 标签:

  • name:属性名,要与类内的属性名一致;
  • value:属性值; 
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book" class="com.demo.pojo.Book">
        <property name="id" value="12"></property>
        <property name="name" value="时间简史"></property>
    </bean>

</beans>

(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 方法注入的区别仅在于 <bean> 标签内的子标签不同,即给属性注入值的标签不同

(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 配置文件中进行配置

写完 <bean> 标签后会报错,因为没有无参构造,所以要添加 <constructor-arg> 标签:

  • name:同类属性名;
  • value:属性值;
  • index:有参构造函数中的第 index 个参数,可以代替 name,但用 name 更直观;
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="order" class="com.demo.pojo.Order">
        <constructor-arg name="name" value="Ds5"/>
        <constructor-arg name="address" value="China"/>
    </bean>
</beans>

(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。

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book" class="com.demo.pojo.Book">
        <property name="id" value="12"></property>
        <property name="name" value="时间简史"></property>
        <property name="price" >
            <null></null>
        </property>
    </bean>
</beans>

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

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

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="book" class="com.demo.pojo.Book">
        <property name="id" value="12"></property>
        <property name="name">
            <value><![CDATA[<<倚天屠龙记>>]]></value>
        </property>
        <property name="price" >
            <null></null>
        </property>
    </bean>
</beans>

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 对象的 <bean> 里的 id 的属性值,这就是注入外部 Bean 的体现;
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userService" class="com.demo.service.impl.UserServiceImpl">
        <property name="userDao" ref="xxx-userDaoImpl"></property>
    </bean>
    <bean id="xxx-userDaoImpl" class="com.demo.dao.impl.UserDaoImpl">

    </bean>

</beans>

(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)输出结果

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:

在 <property> 标签中,嵌套一个 <bean>,即为内部 Bean。

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 内部 bean -->
    <bean id="employee" class="com.demo.pojo.Employee">
        <!-- 先设置普通类型属性 -->
        <property name="name" value="wyt"></property>
        <property name="gender" value="male"></property>
        <!-- 设置对象类型属性 -->
        <property name="department">
            <!-- 嵌套一个 bean -->
            <bean id="department" class="com.demo.pojo.Department">
                <property name="name" value="金融部门"></property>
            </bean>
        </property>
    </bean>

</beans>

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

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

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 级联赋值 -->
    <bean id="employee" class="com.demo.pojo.Employee">
        <!-- 先设置普通类型属性 -->
        <property name="name" value="wyt"></property>
        <property name="gender" value="male"></property>
        <!-- 设置对象类型属性 -->
        <property name="department" ref="department"></property>
    </bean>
    <bean id="department" class="com.demo.pojo.Department">
        <property name="name" value="金融部门"></property>
    </bean>
</beans>


(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)输出结果:

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

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

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 级联赋值 -->
    <bean id="employee" class="com.demo.pojo.Employee">
        <!-- 先设置普通类型属性 -->
        <property name="name" value="wyt"></property>
        <property name="gender" value="male"></property>
        <!-- 设置对象类型属性 -->
        <property name="department" ref="department"></property>
        <property name="department.name" value="技术部门"></property>
    </bean>
    <bean id="department" class="com.demo.pojo.Department"> <!-- 这个 bean 一定要写 -->
        <!-- 这个 property 是没有影响的,会被 employee 中的 property 覆盖 -->
        <property name="name" value="金融部门"></property>
    </bean>
</beans>

(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<String> list;
    private Map<String, String> map;
    private Set<String> set;

    public Set<String> getSet() {
        return set;
    }

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

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

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

    public List<String> getList() {
        return list;
    }

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

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }
}

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

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

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.demo.pojo.Student">
        <!-- 数组类型注入 -->
        <property name="courses">
            <array>
                <value>Java编程</value>
                <value>Sql教学</value>
            </array>
        </property>
        <!-- List 类型注入 -->
        <property name="list">
            <list>
                <value>list01</value>
                <value>list02</value>
            </list>
        </property>
        <!-- Map 类型注入 -->
        <property name="map">
            <map>
                <entry key="1" value="Java编程"></entry>
                <entry key="2" value="Sql教学"></entry>
            </map>
        </property>
        <!-- Set 类型注入 -->
        <property name="set">
            <set>
                <value>set01</value>
                <value>set02</value>
            </set>
        </property>
    </bean>

</beans>

(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)输出结果

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

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

(1)Teacher 类和 Course 类

package com.demo.pojo;

import java.util.List;

public class Teacher {
    private List<Course> courseList;

    public List<Course> getCourseList() {
        return courseList;
    }

    public void setCourseList(List<Course> 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

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

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="teacher" class="com.demo.pojo.Teacher">
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>
    </bean>

    <!-- 创建多个 course bean 对象 -->
    <bean id="course1" class="com.demo.pojo.Course">
        <property name="name" value="Spring5 框架"></property>
    </bean>
    <bean id="course2" class="com.demo.pojo.Course">
        <property name="name" value="MyBatis 框架"></property>
    </bean>

</beans>

(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)输出结果

3、抽取公共属性值

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

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

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

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

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

    <!-- 提取list集合类型属性注入 -->
    <util:list id="languageList"> <!-- map 就用 <util:map>-->
        <!-- 是对象就用 <ref bean="">,是普通类型就用 <value> -->
        <value>Java</value>
        <value>C++</value>
        <value>Python</value>
    </util:list>

    <bean id="list" class="com.demo.pojo.ProgramLanguage">
        <property name="list" ref="languageList"></property>
    </bean>
</beans>

(3)ProgramLanguage 类:

package com.demo.pojo;

import java.util.List;

public class ProgramLanguage {
    private List<String> list;

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> 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)输出结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值