Spring-容器:IOC-基于XML管理Bean

一、概述

1.1、定义

​ IoC (Inversion of Control),即控制反转,是一种设计模式或者说设计思想,它是面向对象编程中的一种概念,用来描述对象之间的依赖关系,指导我们如何设计出松耦合、更优良的程序。

1.2、简介

​ Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别

1.3、作用

​ 在 IoC 模式中,控制权从程序代码中转移到了容器中,即通过容器来管理对象的创建、销毁、依赖注入等操作,而应用程序本身只需要使用这些对象即可。这样,应用程序就不需要自己管理对象之间的依赖关系,而是由容器来管理,从而实现了代码的解耦和更好的可维护性,提高程序扩展力。

说明:

  • 将对象的创建权利交出去,交给第三方容器负责
  • 将对象和对象之间关系的维护权交出去,交给第三方容器负责

在这里插入图片描述

1.4依赖注入

1.4.1定义

​ 依赖注入(Dependency Injection,DI)是一种设计模式,其主要思想是在程序运行的过程中,通过外部容器(如Spring容器)动态地将依赖对象注入到程序中,以解耦对象之间的依赖关系,从而提高程序的灵活性、可维护性和可测试性。

1.4.2作用

Spring通过依赖注入的方式来完成Bean管理的。换句话说,依赖注入,依赖注入实现了控制反转的思想。依赖指的是对象和对象之间的关联关系。注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

补充:

Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

1.4.3实现方式

  • 第一种:set注入
  • 第二种:构造注入

1.5实现

​ Spring 的框架中,IoC 容器是通过 BeanFactoryApplicationContext 接口实现的。

  • BeanFactory 接口是 Spring 框架最底层的接口,提供了基本的 IoC 功能;
  • ApplicationContext 接口是 BeanFactory 接口的子接口,提供了更高级的特性和功能,如 AOP、国际化、事件驱动等。其中BeanFactory 接口,最重要的方法是getBean()方法,用于从容器中获取对象。

ApplicationContext的主要实现类:

在这里插入图片描述
在这里插入图片描述
说明:

​ ApplicationContext有众多的实现类,其中最常用的就是ClassPathXmlApplicationContext与FileSystemXmlApplicationContext实现类

二、基于XML管理Bean(了解)

在这里插入图片描述
在这里插入图片描述

2.1、获取Bean的方式

  • 根据ID获取Bean
    User user = (User) applicationContext.getBean("user");
    
  • 根据类型:
     User user = (User) applicationContext.getBean(User.class);
    
    当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个
  • 根据Id和类型:
    User user = (User) applicationContext.getBean("user", User.class);
    

2.2、依赖注入

在这里插入图片描述

2.2.1、根据setter注入

要有set方法
步骤一:创建学生类Student

package com.atguigu.spring6.bean;

public class Student {

    private Integer id;

    private String name;

    private Integer age;

    private String sex;

    public Student() {
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

}

步骤二:配置bean时为属性赋值

  • property标签:会调用组件类的setXxx()方法给组件对象设置属性
    • name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)
    • value属性:指定属性值
<bean id="studentOne" class="com.atguigu.spring6.bean.Student">
   
    <property name="id" value="1001"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="23"></property>
    <property name="sex" value=""></property>
</bean>

说明:

当使用标签标签完成对象的属性创建时,name需要跟对象中的成员变量同名

步骤三:演示

@Test
public void testDIBySet(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
    Student studentOne = ac.getBean("studentOne", Student.class);
    System.out.println(studentOne);
}

2.2.2、根据构造器注入

步骤一:在基于根据setter注入的基础上,在Student类中添加有参构造

public Student(Integer id, String name, Integer age, String sex) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.sex = sex;
}

步骤二:配置bean

  • constructor-arg标签属性描述构造器参数:
    • index属性:指定参数所在位置的索引(从0开始)
    • name属性:指定参数名,name需要跟对象中的成员变量同名
<bean id="studentTwo" class="com.atguigu.spring6.bean.Student">
    <constructor-arg name="id" value="1002"></constructor-arg>
    <constructor-arg name="name" value="李四"></constructor-arg>
    <constructor-arg name="age"value="33"></constructor-arg>
    <constructor-arg name="sex" value=""></constructor-arg>
</bean>

步骤三:演示

@Test
public void testDIByConstructor(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
    Student studentOne = ac.getBean("studentTwo", Student.class);
    System.out.println(studentOne);
}

2.3、特殊值处理

2.3.1、字面量赋值

<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>

2.3.2、null值

<property name="name">
    <null />
</property>

细节:

<property name="name" value="null"></property>

以上写法,为name所赋值为字符串null

2.3.3、xml实体

<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>

说明:

小于号在XML文档中用来定义标签的开始,不能随便使用

2.3.4、CDATA节

<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <value><![CDATA[a < b]]></value>
</property>

说明:

  • CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据
  • XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析
  • 所以CDATA节中写什么符号都随意

2.4、为对象类型属性赋值

2.4.1、引用外部Bean

在这里插入图片描述

步骤一:配置Clazz类型的bean

<bean id="clazzOne" class="com.atguigu.spring6.bean.Clazz">
    <property name="clazzId" value="1"></property>
    <property name="clazzName" value="英才班"></property>
</bean>

步骤二:为Student中的clazz属性赋值
ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值

<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="id" value="1004"></property>
    <property name="name" value="赵六"></property>
    <property name="age" value="26"></property>
    <property name="sex" value=""></property>
    <!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
    <property name="clazz" ref="clazzOne"></property>
</bean>

2.4.2、引用内部Bean

  • 在一个bean中再声明一个bean就是内部bean
  • 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性
<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="id" value="1004"></property>
    <property name="name" value="赵六"></property>
    <property name="age" value="26"></property>
    <property name="sex" value=""></property>
    <property name="clazz">
        <!-- 在一个bean中再声明一个bean就是内部bean -->
        <!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
        <bean id="clazzInner" class="com.atguigu.spring6.bean.Clazz">
            <property name="clazzId" value="2222"></property>
            <property name="clazzName" value="远大前程班"></property>
        </bean>
    </property>
</bean>

2.4.3、级联属性赋值

<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="id" value="1004"></property>
    <property name="name" value="赵六"></property>
    <property name="age" value="26"></property>
    <property name="sex" value=""></property>
    
    <property name="clazz" ref="clazzOne"></property>
    <property name="clazz.clazzId" value="3333"></property>
    <property name="clazz.clazzName" value="最强王者班"></property>
</bean>

<property name="clazz" ref="clazzOne"></property>
ref不要写成value

2.5、为数组类型属性赋值

步骤一:在Student类中中添加成员变量数组和getter于setter方法

private String[] hobbies;

public String[] getHobbies() {
    return hobbies;
}

public void setHobbies(String[] hobbies) {
    this.hobbies = hobbies;
}

步骤二:配置Bean

<bean id="studentFour" class="com.atguigu.spring.bean6.Student">
    <property name="id" value="1004"></property>
    <property name="name" value="赵六"></property>
    <property name="age" value="26"></property>
    <property name="sex" value=""></property>
    <!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
    <property name="clazz" ref="clazzOne"></property>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
</bean>

2.6、为集合类型属性赋值

2.6.1、注入List集合类型属性值

步骤一:在Clazz类中添加添加成员变量集合和getter于setter方法

private List<Student> students;

public List<Student> getStudents() {
    return students;
}

public void setStudents(List<Student> students) {
    this.students = students;
}

步骤二:配置Bean

<bean id="clazzTwo" class="com.atguigu.spring6.bean.Clazz">
    <property name="clazzId" value="4444"></property>
    <property name="clazzName" value="Javaee0222"></property>
    <property name="students">
        <list>
            <ref bean="studentOne"></ref>
            <ref bean="studentTwo"></ref>
            <ref bean="studentThree"></ref>
        </list>
    </property>
</bean>

细节:

因为List students,List集合中引用的是Student对象,因此注入时需要使用ref标签,进行引用对象

2.6.2、注入Map集合类型属性值

步骤一:创建Student类

package com.atguigu.spring6.bean;
public class Teacher {

    private Integer teacherId;

    private String teacherName;

    public Integer getTeacherId() {
        return teacherId;
    }

    public void setTeacherId(Integer teacherId) {
        this.teacherId = teacherId;
    }

    public String getTeacherName() {
        return teacherName;
    }

    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }

    public Teacher(Integer teacherId, String teacherName) {
        this.teacherId = teacherId;
        this.teacherName = teacherName;
    }

    public Teacher() {

    }
    
    @Override
    public String toString() {
        return "Teacher{" +
                "teacherId=" + teacherId +
                ", teacherName='" + teacherName + '\'' +
                '}';
    }
}

步骤二:在Student类中添加成员变量集合和get于set方法

private Map<String, Teacher> teacherMap;

public Map<String, Teacher> getTeacherMap() {
    return teacherMap;
}

public void setTeacherMap(Map<String, Teacher> teacherMap) {
    this.teacherMap = teacherMap;
}

步骤三:配置bean

<bean id="teacherOne" class="com.atguigu.spring6.bean.Teacher">
    <property name="teacherId" value="10010"></property>
    <property name="teacherName" value="大宝"></property>
</bean>

<bean id="teacherTwo" class="com.atguigu.spring6.bean.Teacher">
    <property name="teacherId" value="10086"></property>
    <property name="teacherName" value="二宝"></property>
</bean>

<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="id" value="1004"></property>
    <property name="name" value="赵六"></property>
    <property name="age" value="26"></property>
    <property name="sex" value=""></property>
    <!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
    <property name="clazz" ref="clazzOne"></property>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
    <property name="teacherMap">
        <map>
            <entry>
                <key>
                    <value>10010</value>
                </key>
                <ref bean="teacherOne"></ref>
            </entry>
            <entry>
                <key>
                    <value>10086</value>
                </key>
                <ref bean="teacherTwo"></ref>
            </entry>
        </map>
    </property>
</bean>

说明:

  • 当注入Map集合类型数据时,需要使用标签
  • 需要使用表示键值对
  • 需要使用表示键

细节:

因为Map<String, Teacher> teacherMap,Map集合中引用的是Teacher对象,因此注入时需要使用标签,进行引用对象

2.6.3、注入引用集合类型属性值

步骤一:配置对应的命名空间

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

步骤二:配置Bean

<!--list集合类型的bean-->
<util:list id="students">
    <ref bean="studentOne"></ref>
    <ref bean="studentTwo"></ref>
    <ref bean="studentThree"></ref>
</util:list>
<!--map集合类型的bean-->
<util:map id="teacherMap">
    <entry>
        <key>
            <value>10010</value>
        </key>
        <ref bean="teacherOne"></ref>
    </entry>
    <entry>
        <key>
            <value>10086</value>
        </key>
        <ref bean="teacherTwo"></ref>
    </entry>
</util:map>
<bean id="clazzTwo" class="com.atguigu.spring6.bean.Clazz">
    <property name="clazzId" value="4444"></property>
    <property name="clazzName" value="Javaee0222"></property>
    <property name="students" ref="students"></property>
</bean>
<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="id" value="1004"></property>
    <property name="name" value="赵六"></property>
    <property name="age" value="26"></property>
    <property name="sex" value=""></property>
    <!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
    <property name="clazz" ref="clazzOne"></property>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
    <property name="teacherMap" ref="teacherMap"></property>
</bean>

在这里插入图片描述

说明:

  • 使用标签,可以将List集合或者Map集合的属性注入变为引用的方式
  • 在使用util标签时,需要引入相应的命名空间

2.7、引入P命名空间属性值

步骤一:引入P命名空间

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

步骤二:通过p命名空间方式为bean的各个属性赋值

<bean id="studentSix" class="com.atguigu.spring6.bean.Student"
    p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></bean>

2.8、引入外部属性文件

步骤一:添加依赖

 <!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>

<!-- 数据源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

步骤二:创建外部属性文件

jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver

说明:

在resources文件下创建jdbc.properties文件

步骤三:引入属性文件

<?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">
    <!-- 引入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
</beans>

注意:

在使用 <context:property-placeholder> 元素加载外包配置文件功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束。

步骤四:配置Bean

<!--完成数据库信息注入-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

说明:

取外部文件中的值时,需要根据外部文件中属性的名字,可以把相应值取得

步骤五:演示

@Test
public void testDataSource() throws SQLException {
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-datasource.xml");
    DataSource dataSource = ac.getBean(DruidDataSource.class);
    Connection connection = dataSource.getConnection();
    System.out.println(connection);
}

2.9、引入Bean的作用域

步骤一:创建类User

package com.atguigu.spring6.bean;
public class User {

    private Integer id;

    private String username;

    private String password;

    private Integer age;

    public User() {
    }

    public User(Integer id, String username, String password, Integer age) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

步骤二:配置bean

属性值:

  • singleton(默认),在IOC容器中,这个bean的对象始终为单实例,当IOC容器初始化时即可创建对象
  • prototype,在IOC容器中,这个bean在IOC容器中有多个实例,当 获取bean时可创建对象
<bean class="com.atguigu.spring6.bean.User" scope="prototype"></bean>

步骤三:演示

@Test
public void testBeanScope(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-scope.xml");
    User user1 = ac.getBean(User.class);
    User user2 = ac.getBean(User.class);
    System.out.println(user1==user2);
}

2.10、Bean的生命周期

2.10.1、Bean实例化基本流程

在这里插入图片描述
在这里插入图片描述

2.10.2、后处理器

在这里插入图片描述

BeanFactoryPostProcessor
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
BeanPostProcessor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.10.3、生命周期

在这里插入图片描述
在这里插入图片描述
Bean实例属性填充
在这里插入图片描述
循环依赖
在这里插入图片描述
在这里插入图片描述
三级缓存
在这里插入图片描述
在这里插入图片描述
总体流程图

在这里插入图片描述

2.11、引入FactoryBean属性值

在这里插入图片描述
说明:

FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。

步骤一 :创建类UserFactoryBean

package com.atguigu.spring6.bean;
public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

步骤二:配置bean

<bean id="user" class="com.atguigu.spring6.bean.UserFactoryBean"></bean>

步骤三:演示

@Test
public void testUserFactoryBean(){
    //获取IOC容器
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-factorybean.xml");
    User user = (User) ac.getBean("user");
    System.out.println(user);
}

说明:

此时获取到的容器对象,并不是UserFactoryBean,而是User

2.12、引入xml自动装配

Control调Service,Service调Dao
步骤一:环境准备

1.创建UserController类

package com.atguigu.spring6.autowire.controller
public class UserController {

    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void saveUser(){
        userService.saveUser();
    }

}

2.创建UserService接口

package com.atguigu.spring6.autowire.service
public interface UserService {

    void saveUser();

}

3.创建UserServiceImpl类实现UserService接口

package com.atguigu.spring6.autowire.service.impl
public class UserServiceImpl implements UserService {

    private UserDao userDao;

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

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

}

4.创建UserDao接口

package com.atguigu.spring6.autowire.dao
public interface UserDao {

    void saveUser();

}

5.创建UserDaoImpl类实现UserDao接口

package com.atguigu.spring6.autowire.dao.impl
public class UserDaoImpl implements UserDao {

    @Override
    public void saveUser() {
        System.out.println("保存成功");
    }

}

步骤二:配置bean

  • 当使用Bean标签的autowire属性是,通过byType的方式进行自动装配
  • byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
    • 若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null
    • 若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
  • byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
<bean id="userController" class="com.atguigu.spring6.autowire.controller.UserController" autowire="byType"></bean>

<bean id="userService" class="com.atguigu.spring6.autowire.service.impl.UserServiceImpl" autowire="byType"></bean>

<bean id="userDao" class="com.atguigu.spring6.autowire.dao.impl.UserDaoImpl"></bean>

步骤三:演示

@Test
public void testAutoWireByXML(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("autowire-xml.xml");
    UserController userController = ac.getBean(UserController.class);
    userController.saveUser();
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值