Maven 依赖引入

一般来说使用Maven进行 jar 包的管理,maven 的使用在此处不多做解释

pom.xml中导入spring-context依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.13</version>
</dependency>

Spirng 核心 API

Spring 核心的 API 为ApplicationContext,它是一个工厂类,用于对象的创建。同时它为了屏蔽实现的差异而被设计成了一个接口,常用的实现方法存在两个

  1. web 环境下使用XmlWebApplicationContext()生产对象,但需要在 maven 中导入spring-webmvc的依赖才可以使用

  2. 其他环境下使用ClassPathXmlApplicationContext()生产对象

对于ApplicationContext,它是一个重量级资源,其生产的对象均会占用大量内存。因此对于一个应用,不要频繁的创建工厂对象 ,一般来说⼀个应用只创建⼀个工厂对象即可(使用单例模式创建对象),同时因为一个应用只拥有一个工厂对象,则ApplicationContext⼀定是线程安全的,支持多线程并发访问

Spring 配置文件

Spring 配置文件的放置位置与命名并没有硬性要求,spring 官方给出的推荐命名方式为applicationContext.xml

当应用 Spring 框架时,需要进行配置文件路径的设置

如果我们采用IDEA新建 spring 配置文件,IDE 会为我们提供一个默认的 schema,在入门阶段使用默认 schma 即可。

我们需要在<beans>标签内写入<bean>标签,配置 Spring 创建的 bean 或组件

Spring 工厂创建的对象被称作 bean 或者组件(componet)

1
2
3
4
5
6
<?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="person" class="com.AnselYuki.Person"/>
</beans>

对于每一个<bean>存在两个必要的属性,分别是idclass,其中id为这个组件的名字,它具有唯一性,而对于class属性,需要使用组件类的全限定名称

在此处我们创建一个 id 为person的 bean,该 bean 对应的类的全限定名称为com.AnselYuki.Person

Spring 工厂相关方法

1
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

运行如上代码,会创建一个工厂类ctx,其主要的作用就是对象的创建,即我们可以通过工厂类获得对象

对于工厂类,具有如下方法(实例基于上文的 Spring 配置文件)

getBean 方法:

该方法负责从 Spring IOC 容器中获取 bean 实例,对于该方法,具有多个方法重载

通过名称获取 bean

对于该方法,传入的单个参数表示组件名称,由于该组件名称在 Spring 配置文件中具有唯一性,此时可以保证创建对象的唯一性

该方法会返回一个Object对象,因此我们需要对它进行强制类型转换

1
Person person = (Person) ctx.getBean("person");

本例中在获取 bean 之后,我们必须将它转换为所需的类型。如果返回的 bean 的类型与我们期望的不同,则可能会产生异常

该方法存在另一个重载,我们只需把目标类的Class实例作为第二个参数调用getBean方法,该方法相较于第一种更加安全,在程序编译阶段就可以发现错误,而不是在运行阶段产生异常

1
Person person = ctx.getBean("person", Person.class);

按类型获取 bean

使用 getBean()时,我们也可以仅指定 bean 的类型,如下所示:

1
Person person = ctx.getBean(Person.class);

在这种情况下,我们需要特别注意可能存在的歧义,在仅指定类型不足以明确确定结果时,我们将得到一个NoUniqueBeanDefinitionException。即在同一个 IOC 容器中如果有相同类型的多个 bean 就不能通过类型获取 bean。

getBeanDefinitionNames 方法

该方法用于获取 Spring 容器中定义的所有JavaBean的名称,即配置文件中所有 bean 标签的 id 值。返回类型是一个字符串数组。

1
2
3
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for(String beanDefinitionName:beanDefinitionNames)
System.out.println(beanDefinitionName);

getBeanNamesForType 方法

该方法用于根据指定对象类型获取 Spring 容器中定义的所有JavaBean的名称,即配置文件中所有 bean 标签的 id 值。返回类型是一个字符串数组。

1
2
3
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
for (String id : beanNamesForType)
System.out.println(id);

containsBeanDefinition 方法

返回类型为布尔类型,判断是否有指定 id 值的 bean 存在于 Spring 工厂内,只可以根据 id 判断是否存在,不能根据 name 值判断存在

1
ctx.containsBeanDefinition("person");

containsBean 方法

返回类型为布尔类型,判断是否有指定 id 值的 bean 存在于 Spring 工厂内,与上一个方法的差异主要在于它不仅可以根据 id 值判断存在,也可以根据 name 值判断存在

1
ctx.containsBean("person"));

Spring 配置文件中需要注意的内容

对一个 bean 只配置 class 属性

1
<bean class="com.AnselYuki.Person"/>

这种语法是 Spring 官方认可的,这种方法会导致 Spring 内部使用全限定名+#+序号的规则生成 id 值,上述配置文件生成的 id 值为com.AnselYuki.Person#0

这种配置的应用场景在于,若该 bean 只需要使用一次,则可以省略它的 id 值,反之若该 bean 需要使用多次或者被其他 bean 引用,则需要设置 id 值

name 属性

「过时的特性」开发中尽量使用 id 属性,name 属性属于历史遗留问题,现代开发中已经基本不会使用到 name 属性

在 Spring 的配置文件中,为 bean 标签定义别名,在使用上 id 与 name 基本一致

1
<bean id="person" name="p" class="com.AnselYuki.Person"/>

id 属性与 name 属性的区别

  1. 别名可以定义多个,但是 id 属性只能有⼀个值,如<bean name="person1,person2" class="com.AnselYuki.Person"/>

  2. XML 文件 id 属性的值具有命名要求:必须以字母开头,可以包含 字母、数字、下划线、连字符;不能以特殊字符开头,如:/person,而 XML 的 name 属性的值,命名没有要求,使用/person也是合法的

但其实 XML 发展到了今天:ID 属性的限制已经不存在,使用/person也是合法的。

思考

未来在开发过程中,是不是所有的对象都会交给 spring 工厂来创建呢?

答案:

理论上来说是的,但是有特例,最大的特例是实体对象(Entity),实体对象会封装数据库中表的数据,交由 spring 工厂创建对象意义不大。我们需要的是实体对象内部数据库的数据,一般来说实体对象交给持久层框架(mybatis 等)进行创建