bean的作用域和生命周期
bean的作用域
在Spring中可以通过配置<bean>
标签的scope
属性来指定bean的作用域范围,各取值含义参加下表:
取值 | 含义 | 创建对象的时机 |
---|---|---|
singleton(默认) | 在IOC容器中,这个bean的对象始终为单实例 | IOC容器初始化时 |
prototype | 这个bean在IOC容器中有多个实例 | 获取bean时 |
如果是在WebApplicationContext环境下还会有另外两个作用域(但不常用):
取值 | 含义 |
---|---|
request | 在一个请求范围内有效 |
session | 在一个会话范围内有效 |
applicationContext.xml
<!--
scope:设置bean的作用域
singleton(默认):bean在IOC容器中只有一个实例,IOC容器初始化时创建对象
prototype:bean在IOC容器中可以有多个实例,getBean()时创建对象
-->
<bean id="StudentFour" class="com.atguigu.spring.Student" scope="prototype">
<property name="id" value="28"></property>
</bean>
SpringTest.java
@Test
public void testBean(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = ioc.getBean("StudentFour",Student.class);
Student student1 = ioc.getBean("StudentFour",Student.class);
System.out.println(student == student1);
}
//运行结果:false
bean的生命周期
具体的生命周期过程
- bean对象创建(调用无参构造器)
- bean对象设置属性(依赖注入)
- bean对象初始化之前操作(由bean的后置处理器
postProcessBeforeInitialization()
方法负责) - ——单例多例执行区别分割线
- bean对象初始化(需在配置bean时指定初始化方法)
- bean对象初始化之后操作(由bean的后置处理器
postProcessAfterInitialization()
方法负责) - bean对象就绪可以使用
- bean对象销毁(需在配置bean时指定销毁方法)
- IOC容器关闭
创建BeanUser.java
为其无参构造、set方法添加对应的输出语句,再添加方法initMethod和destroyMethod并添加对应的输出语句
User.java
public class User {
private Integer id;
private String name;
public User() {
System.out.println("生命周期:1、创建对象");
}
public void setId(Integer id) {
System.out.println("生命周期:2、依赖注入");
this.id = id;
}
public void initMethod(){
System.out.println("生命周期:3、初始化");
}
public void destroyMethod(){
System.out.println("生命周期:5、销毁");
}
//省略了没有输出语句的非特殊方法
applicationContext.xml
<!--
使用init-method属性指定初始化方法
使用destroy-method属性指定销毁方法
-->
<bean id="User" class="com.atguigu.spring.User" init-method="initMethod" destroy-method="destroyMethod">
<property name="id" value="27"></property>
</bean>
SpringTest.java
@Test
public void testBean(){
//ConfigurableApplicationContext是ApplicationContext的子接口,它扩展了刷新和关闭容器的方法
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = ioc.getBean("User",User.class);
System.out.println("生命周期:4、通过IOC容器获取bean并使用");
System.out.println(user);
ioc.close();
}
生命周期:1、创建对象
生命周期:2、依赖注入
生命周期:3、初始化
生命周期:4、通过IOC容器获取bean并使用
User{id=27, name='null'}
生命周期:5、销毁
若bean的作用域为单例,生命周期的前三个步骤会在IOC容器创建时执行
若bean的作用域为多例,生命周期的前三个步骤会在获取bean时执行,且销毁的方法不会再由IOC容器来进行管理
bean的作用域对生命周期的影响
bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行
值得注意的是:bean在实现此接口后,将此bean配置到IOC容器时会导致多例的前三个步骤会和单例一样在创建IOC容器时执行,但功能并不会影响。但是调用getBean方法不会拿IOC容器中已经创建的bean,反而是重新获取新的bean,也就意味着获取bean又会执行一次前三个步骤
BeanPostProcessorTest.java实现BeanPostProcessor接口,重写其中的两个方法
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanPostProcessorTest implements BeanPostProcessor{
//IDEA通过Ctrl+O显示可重写的方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前的操作");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后的操作");
return null;
}
}
因为bean后置处理器只要一个bean实现了接口,对所有bean都生效,所以需要新建一个xml文件
testApplicationContext.xml
<!-- bean的后置处理器要放入IOC容器才能生效 -->
<bean id="BeanPostProcessorTest" class="com.atguigu.spring.BeanPostProcessorTest"></bean>
<bean id="User" class="com.atguigu.spring.User" init-method="initMethod" destroy-method="destroyMethod">
<property name="id" value="27"></property>
</bean>
SpringTest.java
@Test
public void testBean(){
ConfigurableApplicationContext ioc1 = new ClassPathXmlApplicationContext("testApplicationContext.xml");
User user = ioc1.getBean("User",User.class);
System.out.println("生命周期:4、通过IOC容器获取bean并使用");
System.out.println(user);
ioc1.close();
}
生命周期:1、创建对象
生命周期:2、依赖注入
初始化之前的操作
生命周期:3、初始化
初始化之后的操作
生命周期:4、通过IOC容器获取bean并使用
User{id=27, name='null'}
生命周期:5、销毁