Java-30 深入浅出 Spring - IoC 基础 启动IoC 纯XML启动 Bean、DI注入
点一下关注吧!!!非常感谢!!持续更新!!!
大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html
目前已经更新到了:
- MyBatis(已更完)
- Spring(正在更新…)
上节进度
上节我们完成了 启动 IoC 容器 的部分。下面我们续接上节的内容,继续后续的内容。
纯 XML 模式
采用 Spring IoC 和 纯 XML 模式改造之前的 IoC 和 AOP 的实现。
准备工作
我们移除之前 beans.xml 文件,新增:
- applicationContext.xml
创建 Bean 三种方式
之前我们是通过 beans.xml 文件,配合 BeanFactory 来完成对 Bean 的初始化等配置,接下来,我们将使用 Spring 框架来进行配置。
我们在 applicationContext 中配置 bean 之后, 将 Bean 交给 Spring 进行管理。
使用无参构造
在默认情况下,它会通过反射调用无参构造函数来创建对象,如果类中没有无参构造函数,将构建失败。
<bean id="wzkTransferService" class="wzk.service.impl.WzkTransferServiceImpl"></bean>
对应的截图如下所示:
使用静态方法
在实际开发中,我们使用的对象有些时候并不是直接通过构造函数可以创建出来的,它可能在创建的过程中会有很多额外的操作,此时会提供一个创建对象的方法,恰好这个方法是 static 修饰的。
例如,我们 JDBC 的时候,会用到 java.sql.Connection 接口的实现类,如果是 MySQL 数据库,那么用就是 JDBC4Connection,但是我们不会写 JDBC4Connection connection = new JDBC4Connection(),我们要注册驱动,还要提供 URL 等信息。
在实际的开发过程中,尤其早期我们没有使用 Spring 框架来管理和创建对象,但是设计的过程中,使用了工厂模式进行解耦,那么当接入 Spring 之后,就可以采用这种方式了。
我们先放写法:
<bean id="transferService" class="wzk.factory.BeanFactory" factory-method="getTransferService"></bean>
比如说我们有一个单例模式的类,为了保证安全,做了很多操作,而且比如 getInstance() 方法是 static 的。此时用无参构造也是不可行的(private 构造方法),那么我们就需要一个 factory-method 来获取当中的对象。
使用实例化方法创建
此种方法和上面静态方法创建其实类似,区别是用于获取对象的方法不再是static 方式修饰了,而是类中的一个普通的方法,此方法比静态方法创建的几率要高一些。
在早期的项目中,工厂中的方法也可能是静态的,也可能是非静态的,当时非静态的方法的时候,可以采用下面的配置方式:
<bean id="beanFactory" class="wzk.factory.BeanFactory"></bean>
<bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean>
Bean 的生命周期
作用范围改变
在 Spring 框架管理 Bean 对象的创建时,Bean 对象默认都是单例的,但是它支持配置方式改变作用范围,作用范围官方提供的说明如下图:
在上图中提供的这些选项中,我们实际开发中用的最多的就是 Singleton(单例模式)和 prototype(原型模式,也叫多例模式)。
<!--配置service对象-->
<bean id="wzkTransferService"
class="wzk.service.impl.WzkTransferServiceImpl" scope="singleton"></bean>
不同作用范围的生命周期
单例模式:singleton
- 对象初始化:创建容器时,对象就被创建了
- 对象生存:只要容器存在,对象一直活着
- 对象死亡:当容器销毁时,对象就被销毁了
- 一句话总结:单例模式的 bean 对象生命周期与容器相同
多例模式:prototype
- 对象初始化:当使用对象的时候,创建新的对象实例
- 对象生存:只要对象在使用中,就一直活着
- 对象死亡:当对象长时间不用时,被 Java 的垃圾回收器回收了
- 一句话总结:多例模式 bean 对象,Spring 框架只负责创建,不负责销毁
Bean 标签属性
在基于 XML 的 IoC 配置中,Bean 标签是基础的标签,它表示了 IoC
容器中的一个对象,换句话说,如果一个对象让 Spring 管理,在 XML 的配置中都需要使用此标签配置,Bean 标签的属性如下:
- id 属性:用于给 bean 提供一个唯一标识,在一个标签内部,标识必须唯一。
- class 属性:用于指定创建 Bean 对象的全限定类名
- name 属性:用于给 Bean 提供一个或者多个名称,多个名称和空格分隔
- factory-bean 属性:用于指定创建当前 Bean 对象的工厂 Bean 的唯一标识,当指定了此属性之后,class 属性失效
- factory-method 属性:用于指定创建当前 bean 对象的工厂方法,如配置 factory-bean 属性使用,则 class 属性失效,如配合 class 属性使用,则方法必须是 static 的。
- scope 属性:用于指定 bean 对象的作用范围,通常情况下就是 singleton,当用到多例模式的时候,可以配置 prototype。
- init-method 属性:用于指定 bean 对象的初始化方法,此方法会在 bean 对象装配后调用,必须是一个无参方法。
- destory-method 属性:用于指定 bean 对象的销毁方法,此方法 bean 对象销毁前执行,它只能为 scope 是 singleton 时起作用。
DI注入的XML配置
按照注入的方式分类
- 构造函数注入:顾名思义,就是利用带参构造函数实现对类成员的数据赋值
- set 方式注入:它是通过类成员的 set 方法实现数据的注入(使用最多的)
按照注入的数据类型分类
- 基本类型和 String:注入的数据类型是基本类型或者字符串类型的数据
- 其他 Bean 类型:注入的数据类型如果是对象类型的,称为其他 Bean 的原因是,这个对象要求出现在 IoC 容器中,那么对于当前 Bean 来说,就是其他的 Bean 了
- 复杂类型(集合类型):注入的数据类型是 Array,List,Set,Map,Properties 中的一种类型。
构造函数注入
构造函数注入,顾名思义,就是利用构造函数实现对类成员的赋值,它的使用要求是,类中提供的构造函数参数个数必须和配置的参数个数一致,且数据类型匹配。
同时需要注意的是,当没有参数构造时,则必须提供构造函数的注入,否则 Spring 框架会报错。
(代码用之前的)
我们这里可以看看例子,首先我的 WzkTransferServiceImpl 中依赖了 wzkAccountDao,但是我们的代码中,只提供了 set 的方法,而没有提供构造方法。
具体代码在这里:
private WzkAccountDao wzkAccountDao;
public void setWzkAccountDao(WzkAccountDao wzkAccountDao) {
this.wzkAccountDao = wzkAccountDao;
System.out.println("set setWzkAccountDao: " + wzkAccountDao);
}
对应的截图如下所示:
而此时,我们在 applicationContext.xml 中,配置了构造器的注入方式:
<!-- 配置 Bean -->
<bean id="wzkTransferService" class="wzk.service.impl.WzkTransferServiceImpl">
<constructor-arg name="wzkAccountDao" ref="wzkAccountDao"></constructor-arg>
</bean>
我们可以看到已经提示了,没有构造器的话 Spring 是会报错的:
在使用构造函数注入时,涉及的标签时 construct-arg,该标签有 如下的属性:
- name:用于构造函数中指定名称的参数赋值
- index:用于给构造函数中指定索引位置的参数赋值
- value:用于指定基于类型或者 String 类型的数据
- ref:用于指定其他 Bean 类型的数据,写的是其他 Bean 的唯一标识
Set 方法注入
利用提供的 setXxxx 方法来通过赋值的方式实现注入。
编写的 XML 如下:
<bean id="wzkAccountDao" class="wzk.dao.WzkAccountDao"></bean>
<!-- 配置 Bean -->
<bean id="wzkTransferService" class="wzk.service.impl.WzkTransferServiceImpl">
<!-- 构造器注入 -->
<!-- <constructor-arg name="wzkAccountDao" ref="wzkAccountDao"></constructor-arg> -->
<!-- set方法注入 -->
<!-- ref 引入对象 -->
<property name="wzkAccountDao" ref="wzkAccountDao"></property>
<!-- value 是插入值 -->
<property name="name" value="wzkicu"></property>
</bean>
对应的截图如下所示,同样的,如果属性不存在的话,会报错:
在使用 set 方法注入时,需要使用 property 标签,该标签属性如下:
- name:指定注入时调用的 set 方法名称
- value:指定注入的数据,它支持基本类型和 String 类型
- ref:指定注入的数据,它支持其他 bean 类型,写的是其他 bean 的唯一标识
在复杂数据类型注入的时候,指的是集合类型的数据,集合分为两类:
- List 结构
- Map 结构
接下来就是注入的方式的选择,只能在构造函数和 set 方法中选择,我们的示例选用 set 方法注入。
在 List 结构的集合数据注入时,array、list、set 这三个标签通用,另外注值value 标签内部可以直接写值,也可以使用 bean 标签配置一个对象,或者用 ref 标签应用一个已经配合的 bean 的唯一标识。
在 Map 结构的集合数据注入时,map 标签使用 entry 子标签实现数据注入,entry 标签可以使用 key value 属性指定存入 map 中的数据。使用 value-ref 属性指定已经配置好的 bean 的引用。
同事 entry 标签中也可以使用 ref 标签,但是不能使用 bean 标签,而 property标签中不能使用 ref 或者 bean 标签引用对象。