学习目的与要求:
本章主要介绍 Spring Bean 的配置实例化作用域生命周期以及装配方法等内容。通过本章的学习,读者能够了解 Spring Bean 的生命周期,掌握 Spring Bean 的配置、实例化、作用域以及装配方式等内容。
本章主要内容:

  1. Bean 的配置;
  2. Bean 的实例化;
  3. Bean 的作用域;
  4. Bean 的生命周期;
  5. Bean 的装配方法。

在 Spring 的应用中,Spring IoC 容器可以创建、装配和配置应用组件对象,这里的组件对象称为 Bean。本章将重点介绍如何将 Bean 装配注入到 Spring IoC 容器中。

3.1 Bean 的配置

Spring 可以看作一个大型工厂,用于生产和管理 Spring 容器中的 Bean。如果要使用这个工厂生产和管理 Bean,需要开发者将 Bean 配置在 Spring 的配置文件中。Spring框架支持 XML 和 Properties 两种格式的配置文件,在实际开发中常用 XML 格式的配置文件。
XML 的配置文件的根元素是 中包含了多个 子元素,每个 元素定义一个 Bean,并描述 Bean 如何被装配到 Spring 容器中。 元素的常用属性及其子元素如下表所示。

属性或子元素名称 描 述
id Bean 在 BeanFactory 中的唯一标识,在代码中通过 BeanFactory 获取 Bean 实例时需要以此作为索引名称
class Bean 的具体实现类的类名
scope 指定 Bean 实例的作用域
元素的子元素,使用构造方法注入,指定构造方法的参数。该元素的 index 属性指定参数的序号,ref 属性指定对 BeanFactory 中其他 Bean 的引用关系,type 属性指定参数类型,value 属性指定参数的常量值
元素的子元素,用于设置一个属性。该元素的 name 属性指定 Bean 实例中相应的属性名称。value 属性指定 Bean 的属性值,ref 属性指定属性对 BeanFactory 中其他 Bean 的引用关系
元素的子元素,用于封装 List 或数组类型的依赖注入
元素的子元素,用于封装 Map 类型的依赖注入
元素的子元素,用于封装 Set 类型的依赖注入
元素的子元素,用于设置一个键值对。

3.2 Bean 的实例化

在面向对象编程中,如果想使用某个对象,需要实现实例化该对象。同样的,在 Spring 框架中,如果想使用 Spring 容器中的 Bean,也需要实例化 Bean。Spring 框架实例化 Bean 有 3 种方式,即构造方法实例化静态工厂实例化实例工厂实例化(其中最常用的时构造方法实例化)。

3.2.1 构造方法实例化

在 Spring 框架中,Spring 容器可以调用 Bean 对应类中的无参数构造方法来实例化 Bean,这种方式称为构造方法实例化。

  1. 在工程的 src 目录下创建 instance 包,并在该包下创建 BeanClass 类,代码如下:
  1. package instance;
  2. public class BeanClass {
  3. public String message;
  4. public BeanClass(){
  5. message = "构造方法实例化 Bean";
  6. System.out.print(123456);
  7. }
  8. public BeanClass(String s){
  9. System.out.print(123456);
  10. message = s;
  11. }
  12. }
  1. 在工程的 src 目录下创建 Spring 的配置文件 applicationContext.xml,在配置文件中定义一个 id 为 constructorInstance 的 Bean,代码如下:
  1. <!--构造方法实例化Bean-->
  2. <bean id="constructorInstance" class="instance.BeanClass"/>
  1. 在 src 目录下创建 test 包,并在该包下创建测试类 TestInstance,代码如下:
  1. package test;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. import instance.BeanClass;
  5. public class TestInstance {
  6. public static void main(String[] args) {
  7. // 初始化Spring容器ApplicationContext,加载配置文件
  8. ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
  9. // 测试构造方法实例化Bean
  10. BeanClass b1 = (BeanClass)appCon.getBean("constructorInstance");
  11. System.out.println(b1 + b1.message);
  12. }
  13. }

3.2.2 静态工厂实例化

在使用静态工厂实例化 Bean 时,要求开发者在工厂类中创建一个静态方法来创建 Bean 的实例。在配置 Bean 时,class 属性指定静态工厂类,同时还需要使用 factory-method 属性指定工厂类的静态方法

  1. 创建静态工厂类 BeanStaticFactory

在 instance 包中创建工厂类 BeanStaticFactory,该类中有一个静态方法来实例化对象,具体代码如下:

  1. package instance;
  2. public class BeanStaticFactory {
  3. private static BeanClass beanInstance = new BeanClass("调用静态工厂方法实例化Bean");
  4. public static BeanClass createInstance(){
  5. return beanInstance;
  6. }
  7. }
  1. 编辑配置文件

在配置文件 applicationContext.xml 中,添加如下配置代码:

  1. <!--静态工厂方法实例化BeancreateInstance为静态工厂类BeanStaticFactory中的静态方法-->
  2. <bean id="staticFactoryInstance" class="instance.BeanStaticFactory" factory-method="createInstance"/>
  1. 添加配置代码

在测试类 TestInstance 中添加如下代码:

  1. // 静态工厂方法实例化Bean
  2. BeanClass b2 = (BeanClass)appCon.getBean("staticFactoryInstance");
  3. System.out.println(b2 + b2.message);

3.2.3 实例工厂实例化

在使用实例工厂实例化 Bean 时要求开发者在工厂类中创建一个实例方法来创建 Bean 的实例。在配置 Bean 时需要使用 factory-bean 属性指定配置的实例工厂,同时还需要使用 factory-method 属性指定实例工厂中的实例方法。

  1. 创建工厂类 BeanInstanceFactory

在 instance 包中创建工厂类 BeanInstanceFactory,该类中有一个实例方法来实例化对象,具体代码如下:

  1. package instance;
  2. public class BeanInstanceFactory {
  3. // 创建一个实例方法来创建Bean的实例
  4. public BeanClass createBeanClassInstance(){
  5. return new BeanClass("调用实例工厂方法实例化Bean");
  6. }
  7. }
  1. 编辑配置文件

在配置文件 applicationContext.xml 中添加如下配置代码:

  1. <bean id="myFactory" class="instance.BeanInstanceFactory"/>
  2. <!--使用factory-bean属性指定配置工厂,使用factory-method属性指定使用工厂中的哪个方法实例化Bean-->
  3. <bean id="instanceFactoryInstance" factory-bean="myFactory" factory-method="createBeanClassInstance"/>
  1. 添加测试代码

在测试类 TestInstance 中添加如下代码:

  1. // 测试实例工厂实例化Bean
  2. BeanClass b3 = (BeanClass)appCon.getBean("instanceFactoryInstance");
  3. System.out.println(b3 + b3.message);

注意:实例工厂实例化和静态工厂实例化的不同点是一个难点。静态工厂实例化在配置文件中不需要新建一个 bean,只需调用静态方法即可;而实例工厂实例化在配置文件中使用了 factoty-bean = “…” 多创建了一个 bean,原因是实例工厂需要通过 Spring 容器来实例化一个实现类。
具体区别:https://blog.csdn.net/w_linux/article/details/80063062

3.3 Bean的作用域

在 Spring 中不仅可以完成 Bean 的实例化,还可以为 Bean 指定作用域。

作用域名称 描 述
singleton 默认的作用域,使用 singleton 定义的 Bean 在 Spring 容器中只有一个 Bean 实例
prototype Spring 容器每次获取 protorype 定义的 Bean,容器都将创建一个新的 Bean 实例
request 在一次 HTTP 请求中容器将返回一个 Bean 实例,不同的 HTTP 请求返回不同的 Bean实例,仅在 Web Spring 应用程序上下文中使用
session 在一个 Http Session 中,容器将返回同一个 Bean 实例。仅在 Web Spring 应用程序上下文中使用
application 为每个 ServletContext 对象创建一个实例,即同一个应用共享一个 Bean 实例。仅在 Web Spring 应用程序上下文中使用
websocket 为每个 WebSocket 对象创建一个 Bean 实例。仅在 Web Spring 应用程序上下文中使用

在上表中,singleton 和 prototype 是最常用的两种,后面 4 种作用域仅在 Web Spring 应用程序上下文中使用。

3.3.1 singleton 作用域

当将 bean 的 scope 设置为 singleton 时,Spring Ioc 容器仅生成和管理一个 Bean 实例。在使用 id 或 name 获取 Bean 实例时,IoC 容器将返回共享的 Bean 实例。
由于 singleton 是 scope 的默认方法,因此有两种方式将 bean 的 scope 设置为 singleton。配置文件如下:

  1. <bean id="constructorInstance" class="instance.BeanClass">

  1. <bean id="constructorInstance" class="instance.BeanClass" scope="singleton">

使用 id 或 name 获取 Bean 实例时,IoC 容器仅返回同一个 Bean 实例。

3.3.2 prototype 作用域

当将 bean 的 scope 设置为 prototype 时,Spring IoC 容器将为每次请求创建一个新的实例。如果将 3.3.1 中 bean 的配置修改如下:

  1. <bean id="constructorInstance" class="instance.BeanClass" scope="protetype">

使用 id 或 name 两次获取 Bean 实例时,IoC 容器将返回两个不同的 Bean 实例。

3.4 Bean 的生命周期

Bean 的生命周期的整个过程如下:

(1)根据 Bean 的配置情况实例化一个 Bean。
(2)根据 Spring 上下文对实例化的 Bean 进行依赖注入,即对 Bean 的属性进行初始化。
(3)如果 Bean 实现了 BeanNameAware 接口,将调用它实现的 setBeanName(String beanId) 方法,此处参数传递的时 Spring 配置文件中的 Bean 的 id。
(4)如果 Bean 实现了 BeanFactoryAware 接口,将调用它实现的 setBeanFactory 方法,此处参数传递的是当前按 Spring 工厂实例化的引用。
(5)如果 Bean 实现了 ApplicationContextAware 接口,将调用它实现的 setApplicationContext(ApplicatonContext) 方法,此处参数传递的是 Spring 上下文实例的引用。
(6)如果 Bean 关联了 BeanPostProcessor 接口,,将调用初始化方法 postProcessBeforeInitialization(Object obj,String s) 对 Bean 进行操作。
(7)如果 Bean 实现了 InitializingBean 接口,将调用 afterPropertiesSet 方法。
(8)如果 Bean 在 Spring 配置文件中配置了 init-method 属性,将自动调用其配置的初始化方法。
(9)如果 Bean 关联了 BeanPsotProcessor 接口,将调用 postProcessAfterInitialization(Object obj,String s) 方法,由于是在 Bean 初始化结束时调用 After 方法,也可用于内存或缓冲技术。
(10)当 Bean 不再需要时将进入销毁阶段,如果 Bean 实现了 DisposableBean 接口,则调用其实现的 destory 方法将 Spring 中的 Bean 销毁。
(11)如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,将调用其配置的销毁方法进行销毁。

  1. 创建 Bean 的实现类

在工程应用中的 src 目录中创建 life 包,在 life 包创建 BeanLife 类

  1. <bean id="xxx", ...>
  2. <property />
  3. </bean>
  4. =========================
  5. @Controller(xxx)
  6. class Name{
  7. @Autowired
  8. People p;
  9. function(@Autowired People p)
  10. }