第二章 Spring程序初步使用
Maven 依赖引入
一般来说使用Maven
进行 jar 包的管理,maven 的使用在此处不多做解释
在pom.xml
中导入spring-context
依赖
1 | <dependency> |
Spirng 核心 API
Spring 核心的 API 为ApplicationContext
,它是一个工厂类,用于对象的创建。同时它为了屏蔽实现的差异而被设计成了一个接口,常用的实现方法存在两个
web 环境下使用
XmlWebApplicationContext()
生产对象,但需要在 maven 中导入spring-webmvc
的依赖才可以使用其他环境下使用
ClassPathXmlApplicationContext()
生产对象
对于ApplicationContext
,它是一个重量级资源,其生产的对象均会占用大量内存。因此对于一个应用,不要频繁的创建工厂对象 ,一般来说⼀个应用只创建⼀个工厂对象即可(使用单例模式创建对象),同时因为一个应用只拥有一个工厂对象,则ApplicationContext
⼀定是线程安全的,支持多线程并发访问
Spring 配置文件
Spring 配置文件的放置位置与命名并没有硬性要求,spring 官方给出的推荐命名方式为applicationContext.xml
当应用 Spring 框架时,需要进行配置文件路径的设置
如果我们采用
IDEA
新建 spring 配置文件,IDE 会为我们提供一个默认的 schema,在入门阶段使用默认 schma 即可。
我们需要在<beans>
标签内写入<bean>
标签,配置 Spring 创建的 bean 或组件
Spring 工厂创建的对象被称作 bean 或者组件(componet)
1 |
|
对于每一个<bean>
存在两个必要的属性,分别是id
与class
,其中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 | String[] beanDefinitionNames = ctx.getBeanDefinitionNames(); |
getBeanNamesForType 方法
该方法用于根据指定对象类型获取 Spring 容器中定义的所有JavaBean
的名称,即配置文件中所有 bean 标签的 id 值。返回类型是一个字符串数组。
1 | String[] beanNamesForType = ctx.getBeanNamesForType(Person.class); |
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 属性的区别
别名可以定义多个,但是 id 属性只能有⼀个值,如
<bean name="person1,person2" class="com.AnselYuki.Person"/>
XML 文件 id 属性的值具有命名要求:必须以字母开头,可以包含 字母、数字、下划线、连字符;不能以特殊字符开头,如:
/person
,而 XML 的 name 属性的值,命名没有要求,使用/person
也是合法的
但其实 XML 发展到了今天:ID 属性的限制已经不存在,使用
/person
也是合法的。
思考
未来在开发过程中,是不是所有的对象都会交给 spring 工厂来创建呢?
答案:
理论上来说是的,但是有特例,最大的特例是实体对象(Entity),实体对象会封装数据库中表的数据,交由 spring 工厂创建对象意义不大。我们需要的是实体对象内部数据库的数据,一般来说实体对象交给持久层框架(mybatis 等)进行创建