学习目的与要求:
本章主要介绍 Spring Bean 的配置、实例化、作用域、生命周期以及装配方法等内容。通过本章的学习,读者能够了解 Spring Bean 的生命周期,掌握 Spring Bean 的配置、实例化、作用域以及装配方式等内容。
本章主要内容:
- Bean 的配置;
- Bean 的实例化;
- Bean 的作用域;
- Bean 的生命周期;
- Bean 的装配方法。
在 Spring 的应用中,Spring IoC 容器可以创建、装配和配置应用组件对象,这里的组件对象称为 Bean。本章将重点介绍如何将 Bean 装配注入到 Spring IoC 容器中。
3.1 Bean 的配置
Spring 可以看作一个大型工厂,用于生产和管理 Spring 容器中的 Bean。如果要使用这个工厂生产和管理 Bean,需要开发者将 Bean 配置在 Spring 的配置文件中。Spring框架支持 XML 和 Properties 两种格式的配置文件,在实际开发中常用 XML 格式的配置文件。
XML 的配置文件的根元素是
属性或子元素名称 | 描 述 |
---|---|
id | Bean 在 BeanFactory 中的唯一标识,在代码中通过 BeanFactory 获取 Bean 实例时需要以此作为索引名称 |
class | Bean 的具体实现类的类名 |
scope | 指定 Bean 实例的作用域 |
3.2 Bean 的实例化
在面向对象编程中,如果想使用某个对象,需要实现实例化该对象。同样的,在 Spring 框架中,如果想使用 Spring 容器中的 Bean,也需要实例化 Bean。Spring 框架实例化 Bean 有 3 种方式,即构造方法实例化,静态工厂实例化和实例工厂实例化(其中最常用的时构造方法实例化)。
3.2.1 构造方法实例化
在 Spring 框架中,Spring 容器可以调用 Bean 对应类中的无参数构造方法来实例化 Bean,这种方式称为构造方法实例化。
- 在工程的 src 目录下创建 instance 包,并在该包下创建 BeanClass 类,代码如下:
package instance;
public class BeanClass {
public String message;
public BeanClass(){
message = "构造方法实例化 Bean";
System.out.print(123456);
}
public BeanClass(String s){
System.out.print(123456);
message = s;
}
}
- 在工程的 src 目录下创建 Spring 的配置文件 applicationContext.xml,在配置文件中定义一个 id 为 constructorInstance 的 Bean,代码如下:
<!--构造方法实例化Bean-->
<bean id="constructorInstance" class="instance.BeanClass"/>
- 在 src 目录下创建 test 包,并在该包下创建测试类 TestInstance,代码如下:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import instance.BeanClass;
public class TestInstance {
public static void main(String[] args) {
// 初始化Spring容器ApplicationContext,加载配置文件
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
// 测试构造方法实例化Bean
BeanClass b1 = (BeanClass)appCon.getBean("constructorInstance");
System.out.println(b1 + b1.message);
}
}
3.2.2 静态工厂实例化
在使用静态工厂实例化 Bean 时,要求开发者在工厂类中创建一个静态方法来创建 Bean 的实例。在配置 Bean 时,class 属性指定静态工厂类,同时还需要使用 factory-method 属性指定工厂类的静态方法。
- 创建静态工厂类 BeanStaticFactory
在 instance 包中创建工厂类 BeanStaticFactory,该类中有一个静态方法来实例化对象,具体代码如下:
package instance;
public class BeanStaticFactory {
private static BeanClass beanInstance = new BeanClass("调用静态工厂方法实例化Bean");
public static BeanClass createInstance(){
return beanInstance;
}
}
- 编辑配置文件
在配置文件 applicationContext.xml 中,添加如下配置代码:
<!--静态工厂方法实例化Bean,createInstance为静态工厂类BeanStaticFactory中的静态方法-->
<bean id="staticFactoryInstance" class="instance.BeanStaticFactory" factory-method="createInstance"/>
- 添加配置代码
在测试类 TestInstance 中添加如下代码:
// 静态工厂方法实例化Bean
BeanClass b2 = (BeanClass)appCon.getBean("staticFactoryInstance");
System.out.println(b2 + b2.message);
3.2.3 实例工厂实例化
在使用实例工厂实例化 Bean 时要求开发者在工厂类中创建一个实例方法来创建 Bean 的实例。在配置 Bean 时需要使用 factory-bean 属性指定配置的实例工厂,同时还需要使用 factory-method 属性指定实例工厂中的实例方法。
- 创建工厂类 BeanInstanceFactory
在 instance 包中创建工厂类 BeanInstanceFactory,该类中有一个实例方法来实例化对象,具体代码如下:
package instance;
public class BeanInstanceFactory {
// 创建一个实例方法来创建Bean的实例
public BeanClass createBeanClassInstance(){
return new BeanClass("调用实例工厂方法实例化Bean");
}
}
- 编辑配置文件
在配置文件 applicationContext.xml 中添加如下配置代码:
<bean id="myFactory" class="instance.BeanInstanceFactory"/>
<!--使用factory-bean属性指定配置工厂,使用factory-method属性指定使用工厂中的哪个方法实例化Bean-->
<bean id="instanceFactoryInstance" factory-bean="myFactory" factory-method="createBeanClassInstance"/>
- 添加测试代码
在测试类 TestInstance 中添加如下代码:
// 测试实例工厂实例化Bean
BeanClass b3 = (BeanClass)appCon.getBean("instanceFactoryInstance");
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。配置文件如下:
<bean id="constructorInstance" class="instance.BeanClass">
或
<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 的配置修改如下:
<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 的销毁方法,将调用其配置的销毁方法进行销毁。
- 创建 Bean 的实现类
在工程应用中的 src 目录中创建 life 包,在 life 包创建 BeanLife 类
<bean id="xxx", ...>
<property />
</bean>
=========================
@Controller(xxx)
class Name{
@Autowired
People p;
function(@Autowired People p)
}