程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Spring

    • Spring6 - 概述
    • Spring6 - 入门
    • Spring6 - IOC(基于XML)
      • 1. IOC 介绍
      • 2. IOC 容器
        • 2.1 控制反转(IOC)
        • 2.2 依赖注入
        • 2.3 IOC 容器在 Spring 的实现
        • BeanFactory
        • ApplicationContext
        • ApplicationContext的主要实现类
      • 3. 基于 XML 的形式
        • 3.1 创建Maven项目
        • 3.2 配置Maven国内镜像源
        • 3.3 添加Spring框架支持
        • 3.4 创建启动类
        • 3.5 添加Spring配置文件
        • 3.6 配置Bean对象
        • 3.7 获取并使用Bean对象
        • 3.7.1 先获取Spring上下文对象
        • 3.7.2 获取 Bean(根据上下文对象提供的 getBean 方法)
        • (1) 通过 Bean id 来获取
        • (2) 通过类型来获取
        • (3) 通过 id + 类型来获取 (推荐写法)
        • (4) 扩展知识
        • 3.9 依赖注入之 setter 注入
        • 3.10 依赖注入之构造器注入
        • 3.11 特殊值处理
        • 字面量赋值
        • null 值
        • xml 实体
        • CDATA 节
        • 3.12 为对象类型属性赋值
        • 方式一:引用外部 Bean
        • 方式二:内部 Bean
        • 方式三:级联属性赋值
        • 3.13 为数组类型属性赋值
        • 3.14 为集合类型属性赋值
        • 为List集合类型属性赋值
        • 为 Map 集合类型属性赋值
        • 引用集合类型的 Bean
        • 3.15 p 命名空间
        • 3.16 引入外部属性文件
        • 3.17 基于 XML 自动装配
    • Spring6 - IOC(基于注解)
    • spring6 - FactoryBean
    • Spring6 - Bean的作用域
    • Spring6 - Bean生命周期
    • Spring6 - Bean循环依赖
    • Spring6 - 手写IOC容器
    • Spring6 - AOP
    • Spring6 - 自定义注解
    • Spring6 - Junit
    • Spring6 - 事务
    • Spring6 - Resource
    • Spring6 - 国际化
    • Spring6 - 数据校验
    • Spring6 - Cache
    • Spring集成Swagger2
  • Spring生态
  • Spring
scholar
2023-10-27
目录

Spring6 - IOC(基于XML)

# 1. IOC 介绍

IOC 是 Inversion of Control 的简写,译为「控制反转」,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。

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

IOC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。

# 2. IOC 容器

# 2.1 控制反转(IOC)

  • 控制反转是一种思想

  • 控制反转是为了降低程序耦合度,提高程序扩展力

  • 控制反转,反转的是什么?

    • 将对象的创建权利交出去,交给第三方容器负责
    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责
  • 控制反转这种思想如何实现呢?

    • DI(Dependency Injection):依赖注入

# 2.2 依赖注入

DI是"Dependency Injection"的缩写,中文通常翻译为"依赖注入"。它是Spring框架中实现"控制反转"(IOC)思想的一种方式。

  • 依赖注入的基本理念是,一个类不应该自己去创建或查找它所依赖的其他类的实例,而应该由外部(在Spring框架中,通常是Spring的IOC容器)负责这些实例的创建和注入。这样可以将类与类之间的耦合性降低到最低,使得代码更加灵活,更易于测试和维护。
  • 举个例子,假设有一个类A,它需要使用类B的方法。在传统的设计中,A需要自己创建B的实例,或者通过某种方式查找到B的实例。但在依赖注入的设计中,A只需要声明自己需要使用B,Spring框架就会自动将B的实例注入到A中,A直接使用就可以了。

Spring中主要有三种依赖注入的方式:

  • Setter注入:通过调用对象的setter方法来注入依赖。
  • 构造方法注入:通过构造器来注入依赖。
  • 属性注入:直接将依赖注入到字段中。

简而言之,IOC是一种设计思想 ,而 DI 是对 IOC 的一种具体实现。

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

# 2.3 IOC 容器在 Spring 的实现

Spring 的 IOC 容器就是 IOC 思想的一个落地的产品实现。IOC 容器中管理的组件也叫做 Bean。在创建 Bean 之前,首先需要创建 IOC 容器。Spring 提供了 IOC 容器的两种实现方式:

image-20240223044357248

# BeanFactory

  • 基础:BeanFactory是Spring容器的最基础形式,提供了基本的容器功能,主要负责的是配置、创建和管理bean。
  • 惰性初始化:当使用BeanFactory加载配置文件时,它不会立即创建配置文件中定义的bean。只有在第一次请求(通过getBean方法)某个bean时,才会创建该bean实例。这种行为被称为“惰性初始化”或“延迟加载”。
  • 面向Spring本身:BeanFactory是面向Spring内部使用的低级接口,不推荐开发人员直接使用。

# ApplicationContext

  • 高级特性:ApplicationContext是BeanFactory的子接口,添加了更多企业级功能。它完全覆盖了BeanFactory的功能,并提供了额外的支持,如国际化、事件传播、资源加载等。
  • 饥饿加载:当使用ApplicationContext时,容器在启动时会立即创建并初始化所有的单例bean(除非指定了延迟初始化)。这种行为被称为“饥饿加载”或“预加载”。
  • 面向使用者:ApplicationContext是面向Spring的终端用户设计的,提供了配置和管理bean的高级接口。在实际开发中,几乎所有的场景都会使用ApplicationContext而不是直接使用BeanFactory。

# ApplicationContext的主要实现类

image-20240221184228927

  • ClassPathXmlApplicationContext:
    • 这是一个常用的实现类,它从类路径(即项目的resources目录下)加载XML配置文件。通过这种方式,你可以将Spring的配置文件放在Java项目的资源目录下,然后通过这个类读取配置,初始化Spring容器。
  • FileSystemXmlApplicationContext:
    • 如果你的Spring配置文件不在类路径下,而是在文件系统的某个位置,那么可以使用这个实现类。它可以加载任意路径下的XML配置文件来初始化Spring容器。这个路径可以是绝对路径,也可以是相对路径。
  • ConfigurableApplicationContext:
    • 这是一个扩展的ApplicationContext接口,提供了一些额外的功能,如刷新和关闭容器。refresh()方法可以重新加载配置和重新初始化容器,而close()方法可以关闭容器,释放资源。
  • WebApplicationContext:
    • 专门为Web应用设计的ApplicationContext实现,它在普通的ApplicationContext基础上添加了对Web环境的支持。通过将Spring容器与Servlet容器(如Tomcat)集成,可以实现在Web应用运行时管理和访问Spring容器。

# 3. 基于 XML 的形式

# 3.1 创建Maven项目

  1. 启动IntelliJ IDEA:打开IntelliJ IDEA,等待其加载完成。
  2. 创建新项目:选择菜单栏中的File > New > Project,这会打开创建新项目的向导。
  3. 选择项目类型:在左侧的项目类型列表中,选择Maven。确保右侧的选项中已经勾选了Create from archetype选项,然后点击Next继续。
  4. 填写项目信息:在接下来的页面中,填写GroupId(通常是组织或公司的域名倒序,如com.example)、ArtifactId(项目名,如demo)、Version(版本号,如果是新项目,通常使用1.0-SNAPSHOT)。填写完成后,点击Next。
  5. 项目名称和位置:填写项目的名称,并选择一个合适的目录作为项目的位置。完成后,点击Finish按钮,IntelliJ IDEA会为你创建一个新的Maven项目。

# 3.2 配置Maven国内镜像源

为了加快依赖下载速度,避免网络问题,推荐配置国内的Maven镜像源。下面以配置阿里云Maven镜像为例:

  1. 打开Maven的配置文件:找到你的Maven安装目录,编辑conf文件夹下的settings.xml文件。如果你是通过IntelliJ IDEA管理Maven的,可以在IDEA的Settings或Preferences中找到Maven设置,从而直接编辑settings.xml文件。

  2. 添加镜像源:在<mirrors>标签内添加一个新的<mirror>标签,配置如下:

    <mirror>
        <id>aliyunmaven</id>
        <mirrorOf>*</mirrorOf>
        <name>阿里云公共仓库</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
    
    1
    2
    3
    4
    5
    6
  3. 保存并重启IDEA:保存settings.xml文件的修改,并重启IntelliJ IDEA,以便更改生效。

通过上述步骤,你的Maven项目将会从阿里云的镜像源下载依赖,这通常会比从默认的Maven中央仓库下载速度更快,更稳定。

注意:在配置镜像源时,请确保你选择的镜像源是可信赖的,因为错误或过时的镜像源可能会影响项目依赖的正确性和安全性。

# 3.3 添加Spring框架支持

大家可以去中央仓库拉取, 也可以直接复制下面代码粘贴到 Spring 项目中 pom.xml 下 dependencies标签中.

在pom.xml中添加Spring的框架支持,xml配置如下:

<dependencies>
    <!--Spring context依赖-->
    <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
    <dependency>
        <groupId>org.Springframework</groupId>
        <artifactId>Spring-context</artifactId>
        <version>6.1.5</version>
    </dependency>

    <!--junit5测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.3.1</version>
    </dependency>

    <!--log4j2的依赖-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.19.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j2-impl</artifactId>
        <version>2.19.0</version>
    </dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

【注意事项】

我们在添加完依赖时, 一定要切记点击 IDEA 右边 maven 的 Reload, 如果 IDEA 项目中出现下图中相关依赖信息, 则表示添加依赖成功了.

image-20240402020108155

# 3.4 创建启动类

创建一个包含main方法的启动类。这个类将作为整个应用的入口点。例如,创建一个名为Application的类:

public class Application {
    public static void main(String[] args) {
        // Spring 应用启动逻辑
    }
}
1
2
3
4
5

# 3.5 添加Spring配置文件

为了让Spring框架能够了解你的Bean配置,需要创建一个Spring配置文件。通常,这个配置文件被命名为spring-config.xml,位于资源文件夹resources下。

  1. 在src/main/resources目录下创建一个新的文件,命名为spring-config.xml(命名可以随意)。
  2. 在这个XML文件中,定义Spring Beans的配置,文件内容如下:
<?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的定义 -->
</beans>
1
2
3
4
5
6
7

# 3.6 配置Bean对象

在spring-config.xml文件中,你可以通过<bean>标签来定义和配置Bean:

<bean id="student" class="com.scholar.spring6.Student"></bean>
1

在上面的例子中,id属性用于指定Bean的唯一标识符,class属性用于指定Bean的全类名。这告诉Spring容器,当应用启动时,需要创建一个student的实例,并将其注册到Spring上下文中。

经过以上操作, 我的 bean 对象是否已经存储到 Spring 中了呢 ?

其实并没有, 上述操作只是声明了我要存储对象到 Spring 当中. 当程序正儿八经的执行的时候, Spring 采用的是懒加载, 在启动 Spring 项目的时候, 它不会立即的去将 bean 存储到 Spring 中, 这是它实现上的一个策略, 这也是广义上和狭义上的一个区别, 就类似于并发和并行两者之间的区别一样, 初学的时候, 站在广义的角度上便于理解.

# 3.7 获取并使用Bean对象

使用Spring上下文的方式获取Bean对象

  1. 先获取Spring上下文对象(ApplicationContext的实例)
  2. 再通过上下文对象提供的方法获取指定的Bean对象

# 3.7.1 先获取Spring上下文对象



 
 








public class Application {
    public static void main(String[] args) {
        //1. 获取Spring上下文对象(ApplicationContext的实例)
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //2.从spring容器中获取 Bean 对象 ,此处的"student" 必须和spring-config.xml配置中的Bean的id保持一致
        //getBean的返回类型为Object,所以强转一下
        Student student =(Student) context.getBean("student"); //该行代码就是实现IOC思想的DI操作
        //3.使用Bean对象(非必须,也可以获取不用)
        student.sayHi();
    }
}
1
2
3
4
5
6
7
8
9
10
11

image-20240402022653893

除了这种方法可以拿到 Spring 上下文对象之外, 我们还可以使用 BeanFactory来作为 Spring 上下文对象. 使用 ApplicationContext 或者 BeanFactory 来获取 Spring 上下文对象, 是同样的效果, 只不过 ApplicaitonContext 是 BeanFactory 的一个子类.

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
1

# 3.7.2 获取 Bean(根据上下文对象提供的 getBean 方法)

image-20240224223559897

# (1) 通过 Bean id 来获取

//根据上下文提供的方法获取bean对象
Student student =(Student) context.getBean("student"); 
1
2

image-20240402024016103

# (2) 通过类型来获取

//通过类型获取bean对象
Student student =context.getBean(Student.class);
1
2

虽然写法简单,但是容易出问题,当同一个类型被注入 Spring 中多次(多个)的时候,就会报错

image-20240402023608858

# (3) 通过 id + 类型来获取 (推荐写法)

为了结合上述两种方式的优点,并避免它们的缺陷,Spring还提供了通过id加类型同时获取Bean实例的方法。这种方式即确保了类型的安全性,也避免了因类型重复而产生的歧义:

//通过id+类型获取bean对象
Student student =context.getBean("student",Student.class);
1
2

这种方法是最推荐的方式,它既保证了通过id的唯一性来精确定位Bean,又通过类型确认了返回对象的类型安全,避免了强制类型转换的风险。此外,如果在Spring容器中存在多个同类型的Bean,使用这种方式可以精确地获取到指定id的Bean,从而避免了潜在的冲突和错误。

image-20240402023807691

# (4) 扩展知识

如果组件类实现了接口,根据接口类型可以获取 Bean 吗?

可以,前提是 Bean 唯一

如果一个接口有多个实现类,这些实现类都配置了 Bean,根据接口类型可以获取 Bean 吗?

不行,因为 Bean 不唯一

测试通过接口类型来获取实现类的Bean

image-20240222075229373

image-20240222075301335

image-20240222075452260

# 3.9 依赖注入之 setter 注入

创建学生类 Student

package com.boge.spring.bean;

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String gender;

    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 getGender() {
        return gender;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

然后我们的配置文件中通过 property标签来完成setter注入:这里的name属性对应于Student类中的setter方法名称,而value属性则是要注入的具体值。

<bean id="student" class="com.scholar.spring6.Student">
    <!-- property 标签:通过组件类的 setXxx() 方法给组件对象设置属性 -->
    <!-- name 属性:指定属性名(这个属性名是 getXxx()、setXxx() 方法定义的,和成员变量无关) -->
    <!-- value 属性:指定属性值 -->
    <property name="id" value="1001"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="23"></property>
    <property name="gender" value="男"></property>    
</bean>
1
2
3
4
5
6
7
8
9

当Spring框架加载这个XML配置文件时,它会根据<bean>标签中的class属性创建Student对象的实例,然后根据<property>标签的指定,通过反射调用setter方法,将配置文件中定义的值注入到Student对象的相应属性中。

image-20240402030718091

在这儿需要注意。对应的属性我们必须要提供setter方法。

image-20240402030831169

# 3.10 依赖注入之构造器注入

针对上面的设置注入中的必要条件是对应的属性必须添加相关的setter方法。我们可以通过构造注入的方式来解决。

package com.scholar.spring6;

public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String gender;

    // 构造函数
    public User(Integer id, String name, Integer age, String gender) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    // 无参构造函数(如果有其他构造函数,无参构造函数也需要显式定义)
    public User() {
    }

    // toString方法用于打印对象信息
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

在Spring的XML配置文件中,我们通过<bean>标签定义User类的Bean,并使用<constructor-arg>子标签来注入构造函数的参数。这里的<constructor-arg>标签可以通过index、name或直接提供value来指定参数值。

<bean class="com.scholar.spring6.User">
    <!-- 使用constructor-arg标签进行构造器注入 -->
    <constructor-arg index="0" value="10086"></constructor-arg>
    <constructor-arg index="1" value="boge"></constructor-arg>
    <constructor-arg index="2" value="20"></constructor-arg>
    <constructor-arg index="3" value="女"></constructor-arg>
</bean>
1
2
3
4
5
6
7

注意事项

  • constructor-arg标签:用于指定构造函数的参数,可以通过index指定参数的位置(从0开始)、name指定参数名称,或者直接使用value属性来传递参数值。
  • index属性:表示该参数在构造函数参数列表中的位置,从0开始编号。
  • name属性:表示构造函数中参数的名称,这要求编译后的类文件保留参数名信息(Java 8+提供了这种能力),否则可能无法通过名称匹配参数

然后对应的执行效果

image-20240402031124986

# 3.11 特殊值处理

# 字面量赋值

字面量指的是数据的直接表示,比如数字 10、字符串 "hello" 等。在 Spring 的 XML 配置中,我们可以直接通过 value 属性为 Bean 的属性赋予字面量值。

<!-- 将 name 属性的值设置为字符串 "张三" -->
<property name="name" value="张三"/>
1
2

# null 值

在一些场景下,我们可能需要将 Bean 的某个属性显式地设置为 null。由于直接在 value 中赋值 "null" 字符串并不代表真正的 null 值,Spring 提供了 <null/> 标签来表示属性值为 null。

<!-- 显式地将 name 属性设置为 null -->
<property name="name">
    <null />
</property>
1
2
3
4

注意事项

  1. 字面量赋值:使用 value 属性进行赋值时,Spring 会把这个值当作字面量处理。这意味着,如果你写 value="10",Spring 会把这个值当作数字 10 处理;如果写 value="hello",则处理为字符串 "hello"。

  2. null 值处理:当需要为属性赋 null 值时,必须使用 <null/> 标签。直接使用 value="null" 实际上会将属性设置为字符串 "null",而不是 null 值。

# xml 实体

在 Spring 的 XML 配置文件中,我们有时候需要处理特殊字符,如小于号 <。由于 < 在 XML 中用于定义标签的开始,直接使用可能会导致 XML 解析错误。为了在 XML 文件中正确表示这类特殊字符,我们可以使用 XML 实体或 CDATA 节。

XML 实体是一种特殊的标记,它允许我们在 XML 文档中使用那些在 XML 中有特殊意义的字符。常用的 XML 实体包括:

  • < 代表小于号 <
  • > 代表大于号 >
  • & 代表和号 &
  • " 代表双引号 "
  • ' 代表单引号 '

例如,当我们需要在 XML 文件中表示 a < b 这样的表达式时,可以使用 < 来代替小于号

<!-- 使用 XML 实体 &lt; 代替小于号,避免 XML 解析错误 -->
<property name="expression" value="a &lt; b"/>
1
2

# CDATA 节

另一种处理 XML 中特殊字符的方法是使用 CDATA 节。CDATA 节被用来告诉 XML 解析器,它所包含的内容应该被当作字符数据处理,而不是 XML 标记。在 CDATA 节中,你可以自由地使用任何字符,包括那些在 XML 中有特殊含义的字符。

CDATA 节的语法是 <![CDATA[内容]]>。例如,要在 XML 配置中使用 a < b,可以将其放在 CDATA 节中:

<property name="expression">
    <!-- 使用 CDATA 节包裹特殊字符或表达式,确保它们被当作文本处理 -->
    <!-- CDATA 节中的内容不会被 XML 解析器解析为 XML 标记或属性 -->
    <value><![CDATA[a < b]]></value>
</property>
1
2
3
4
5

注意事项

  • 使用 XML 实体 是处理单个特殊字符的简便方法,特别适用于简短的文本或属性值中。
  • 当需要在配置中包含较长的文本或包含多个特殊字符时,CDATA 节 提供了一种更灵活的解决方案。
  • 在使用 CDATA 节时,需要注意它的开始标记 <![CDATA[ 和结束标记 ]]>,确保它们正确无误。

# 3.12 为对象类型属性赋值

创建班级 类Clazz

package cn.youngkbt.Spring6.Bean
    
public class Clazz {

    private Integer clazzId;

    private String clazzName;

    public Integer getClazzId() {
        return clazzId;
    }

    public void setClazzId(Integer clazzId) {
        this.clazzId = clazzId;
    }

    public String getClazzName() {
        return clazzName;
    }

    public void setClazzName(String clazzName) {
        this.clazzName = clazzName;
    }

    @Override
    public String toString() {
        return "Clazz{" +
                "clazzId=" + clazzId +
                ", clazzName='" + clazzName + '\'' +
                '}';
    }

    public Clazz() {
    }

    public Clazz(Integer clazzId, String clazzName) {
        this.clazzId = clazzId;
        this.clazzName = clazzName;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

修改 Student 类

在 Student 类中添加以下代码:

private Clazz clazz;

public Clazz getClazz() {
	return clazz;
}

public void setClazz(Clazz clazz) {
	this.clazz = clazz;
}
1
2
3
4
5
6
7
8
9

# 方式一:引用外部 Bean

首先,我们可以在 Spring 配置文件中单独配置 Clazz 类的 Bean,并通过 ref 属性在 Student 的配置中引用这个外部 Bean。这种方式允许我们在多个地方重用同一个 Bean 定义。

定义 Clazz 类的 Bean:

<!-- 定义一个Clazz类型的Bean -->
<Bean id="clazzOne" class="cn.youngkbt.Spring6.Bean.Clazz">
    <property name="clazzId" value="1111"></property>
    <property name="clazzName" value="财源滚滚班"></property>
</Bean>
1
2
3
4
5

为 Student 类的 clazz 属性引用 Clazz 类的 Bean:

<!-- 通过ref属性引用定义好的Clazz Bean -->
<Bean id="studentFour" class="cn.youngkbt.Spring6.Bean.Student">
    ...
    <property name="clazz" ref="clazzOne"></property>
</Bean>
1
2
3
4
5

错误演示:

<Bean id="studentFour" class="cn.youngkbt.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" value="clazzOne"></property>
</Bean>
1
2
3
4
5
6
7

如果错把 ref 属性写成了 value 属性,会抛出异常:

Caused by: Java.lang.IllegalStateException: Cannot convert value of type 'Java.lang.String' to required type 
'cn.youngkbt.Spring6.Bean.Clazz' for property 'clazz': no matching editors or conversion strategy found
1
2

意思是不能把 String 类型转换成我们要的 Clazz 类型,说明我们使用 value 属性时,Spring 只把这个属性看做一个普通的字符串,不会认为这是一个 Bean 的 id,更不会根据它去找到 Bean 来赋值。

# 方式二:内部 Bean

我们还可以直接在 Student 类的配置中定义一个内部的 Clazz Bean,这种内部 Bean 仅在包含它的外部 Bean 中有效,适用于当这个对象仅被一个 Bean 使用时的情况。

定义内部 Clazz Bean:

<Bean id="studentFour" class="cn.youngkbt.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 只能用于给属性赋值,不能在外部通过 XML 容器获取,因此可以省略 id 属性 -->
        <Bean id="clazzInner" class="cn.youngkbt.Spring6.Bean.Clazz">
            <property name="clazzId" value="2222"></property>
            <property name="clazzName" value="远大前程班"></property>
        </Bean>
    </property>
</Bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 方式三:级联属性赋值

级联属性赋值允许我们在不直接定义内部 Bean 的情况下,通过 . 语法直接设置某个属性的内部属性值。这种方式特别适用于已经通过 ref 引用了外部 Bean,但需要调整这个 Bean 的某些属性的场景。

使用级联属性为 Clazz 类的属性赋值:

<!-- 通过级联属性为Clazz类的属性赋值 -->
<Bean id="studentFour" class="cn.youngkbt.Spring6.Bean.Student">
    ...
    <property name="clazz" ref="clazzOne"></property>
    <!-- 直接设置clazz属性的内部属性 -->
    <property name="clazz.clazzId" value="3333"></property>
    <property name="clazz.clazzName" value="最强王者班"></property>
</Bean>
1
2
3
4
5
6
7
8

# 3.13 为数组类型属性赋值

修改Student类

在 Student 类中添加以下代码:

private String[] hobbies;

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

public void setHobbies(String[] hobbies) {
    this.hobbies = hobbies;
}
1
2
3
4
5
6
7
8
9

配置 Bean:注入到容器中的Bean的属性中可能是数组类型。那么这时我们可以通过array标签来完成赋值

<Bean id="studentFour" class="cn.youngkbt.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属性:引用XML容器中某个Bean的id,将所对应的Bean为属性赋值 -->
    <property name="clazz" ref="clazzOne"></property>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
</Bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.14 为集合类型属性赋值

# 为List集合类型属性赋值

在 Clazz 类中添加以下代码:

private List<Student> students;

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

public void setStudents(List<Student> students) {
    this.students = students;
}
1
2
3
4
5
6
7
8
9

配置 Bean:注入到容器中的Bean的属性可能是List集合。那么我们需要通过list标签来完成属性的赋值

<Bean id="clazzTwo" class="cn.youngkbt.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>
1
2
3
4
5
6
7
8
9
10
11

若为 Set 集合类型属性赋值,只需要将其中的 list 标签改为 set 标签即可

# 为 Map 集合类型属性赋值

创建教师类 Teacher:

package cn.youngkbt.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 + '\'' +
                '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

在 Student 类中添加以下代码:

private Map<String, Teacher> teacherMap;

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

public void setTeacherMap(Map<String, Teacher> teacherMap) {
    this.teacherMap = teacherMap;
}
1
2
3
4
5
6
7
8
9

配置 Bean:


























 
 
 
 
 
 
 
 
 
 
 
 
 
 



<Bean id="teacherOne" class="cn.youngkbt.Spring6.Bean.Teacher">
    <property name="teacherId" value="10010"></property>
    <property name="teacherName" value="大宝"></property>
</Bean>

<Bean id="teacherTwo" class="cn.youngkbt.Spring6.Bean.Teacher">
    <property name="teacherId" value="10086"></property>
    <property name="teacherName" value="二宝"></property>
</Bean>

<Bean id="studentFour" class="cn.youngkbt.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 属性:引用 XML 容器中某个 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 引用集合类型的 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="cn.youngkbt.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="cn.youngkbt.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 属性:引用 XML 容器中某个 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

使用 util:list、util:map 标签必须引入相应的命名空间

<?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">
1
2
3
4
5
6
7
8

# 3.15 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">
1
2
3
4
5
6
7
8
9

引入 p 命名空间后,可以通过以下方式为 Bean 的各个属性赋值

<Bean id="studentSix" class="cn.youngkbt.Spring6.Bean.Student"
    p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></Bean>
1
2

# 3.16 引入外部属性文件

加入依赖

 <!-- 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>
1
2
3
4
5
6
7
8
9
10
11
12
13

创建外部属性文件

images

jdbc.user=root
jdbc.password=youngkbt
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
1
2
3
4

引入属性文件

引入 context 名称空间

<?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">

</Beans>
1
2
3
4
5
6
7
8
9
10
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
1
2

注意:在使用 context:property-placeholder 元素加载外包配置文件功能前,首先需要在 XML 配置的一级标签 <Beans> 中添加 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>
1
2
3
4
5
6

测试

@Test
public void testDataSource() throws SQLException {
    ApplicationContext ac = new ClassPathXmlApplicationContext("Spring-datasource.xml");
    DataSource dataSource = ac.getBean(DataSource.class);
    Connection connection = dataSource.getConnection();
    System.out.println(connection);
}
1
2
3
4
5
6
7

# 3.17 基于 XML 自动装配

自动装配:

根据指定的策略,在 XML 容器中匹配某一个 Bean,自动为指定的 Bean 中所依赖的类类型或接口类型属性赋值

场景模拟

创建类 UserController

package cn.youngkbt.Spring6.autowire.controller
public class UserController {

    private UserService userService;

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

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

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

创建接口 UserService

package cn.youngkbt.Spring6.autowire.service
public interface UserService {

    void saveUser();

}
1
2
3
4
5
6

创建类 UserServiceImpl 实现接口 UserService

package cn.youngkbt.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();
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

创建接口 UserDao

package cn.youngkbt.Spring6.autowire.dao
public interface UserDao {

    void saveUser();

}
1
2
3
4
5
6

创建类 UserDaoImpl 实现接口 UserDao

package cn.youngkbt.Spring6.autowire.dao.impl
public class UserDaoImpl implements UserDao {

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

}
1
2
3
4
5
6
7
8
9

配置Bean

使用 Bean 标签的 autowire 属性设置自动装配效果

自动装配方式:byType

byType:根据类型匹配XML容器中的某个兼容类型的 Bean,为属性自动赋值

若在 XML 中,没有任何一个兼容类型的 Bean 能够为属性赋值,则该属性不装配,即值为默认值 null

若在 XML 中,有多个兼容类型的 Bean 能够为属性赋值,则抛出异常 NoUniqueBeanDefinitionException

<Bean id="userController" class="cn.youngkbt.Spring6.autowire.controller.UserController" autowire="byType"></Bean>

<Bean id="userService" class="cn.youngkbt.Spring6.autowire.service.impl.UserServiceImpl" autowire="byType"></Bean>

<Bean id="userDao" class="cn.youngkbt.Spring6.autowire.dao.impl.UserDaoImpl"></Bean>
1
2
3
4
5

自动装配方式:byName

byName:将自动装配的属性的属性名,作为 Bean 的 id 在 XML 容器中匹配相对应的 Bean 进行赋值

<Bean id="userController" class="cn.youngkbt.Spring6.autowire.controller.UserController" autowire="byName"></Bean>

<Bean id="userService" class="cn.youngkbt.Spring6.autowire.service.impl.UserServiceImpl" autowire="byName"></Bean>
<Bean id="userServiceImpl" class="cn.youngkbt.Spring6.autowire.service.impl.UserServiceImpl" autowire="byName"></Bean>

<Bean id="userDao" class="cn.youngkbt.Spring6.autowire.dao.impl.UserDaoImpl"></Bean>
<Bean id="userDaoImpl" class="cn.youngkbt.Spring6.autowire.dao.impl.UserDaoImpl"></Bean>
1
2
3
4
5
6
7

测试

@Test
public void testAutoWireByXML(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("autowire-xml.xml");
    UserController userController = ac.getBean(UserController.class);
    userController.saveUser();
}
1
2
3
4
5
6
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
Spring6 - 入门
Spring6 - IOC(基于注解)

← Spring6 - 入门 Spring6 - IOC(基于注解)→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式