去一些企业面试时,经常会被问到Spring的问题,有一次就被问到关于Spring中Bean的生命周期是怎样的?其实这也是在业务中经常会遇到的问题,但容易遗忘,所以这次专门总结一下。
提示:可以借鉴Servlet的生命周期,实例化、初始init、接收请求service、销毁destroy。
Bean 的完整生命周期
对于普通的Java对象,当new的时候创建对象,当它没有任何引用的时候被垃圾回收机制回收。而由Spring IoC容器托管的对象,它们的生命周期完全由容器控制。Spring中每个Bean的生命周期如下:
如上图所示,Bean的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:
Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化;
Bean实例化后对将Bean的引入和值注入到Bean的属性中;
如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法;
如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来;
如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法;
如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用;
如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法;
此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁;
如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
说实话,看了这么多面试题,只有这道面试题的答案内容是最多的,其实很多时候我们并不会真的去实现上面所描述的那些接口,如果在面试时被问到Spring Bean生命周期,我相信很多人说不出来,以下我分了三个阶段来深入了解下bean的生命周期,让小伙伴有更加深刻的理解!
生命周期的三个阶段
先补充下spring的作用域
目前Spring Bean的作用域或者说范围主要有五种。
第一创建阶段
Spring工厂何时创建对象
scope = “singleton”(默认)
```java
Spring工厂创建的同时,对象创建
ClassPathXmlApplicationContext s1 = new ClassPathXmlApplicationContext("application.xml");
注意:lazy-init="true" 这种情况下是在获取对象的时候才创建
<bean name="student" class="com.zq.student" scope="singleton" lazy-init="true"/>
```
scope = “prototype”
```java
Spring工厂在获取对象的时候创建对象.
ClassPathXmlApplicationContext s1 = new ClassPathXmlApplicationContext("application.xml");
Object student = s1.getBean("student");
```
第二初始化阶段
Spring工厂在创建完成对象后,调用对象的初始化方法,完成对应的初始化操作
1. 初始化方法提供: 程序员根据需求,提供初始化方法,最终完成初始化操作
2. 初始化方法调用: Spring工厂进行调用
InitializingBean接口
```java
实现接口 重写方法
@Override
public void afterPropertiesSet() throws Exception {
//这里写初始化的内容.数据库?
System.out.println("初始化方法");
}
```
自己提供一个普通方法 配置到 配置文件
```java
public void myInit(){
System.out.println("我自己定义的初始化方法");
}
<bean name="student" class="com.zq.student" init-method="myInit" />
```
细节分析
1.既实现了 InitializingBean 又自己定义了 执行顺序?
```java
1. InitializingBean接口
2. 自定义的初始化
```
2.注入一定发生在初始化操作前面
```java
public class student implements InitializingBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("student的set方法");
this.name = name;
}
public student() {
System.out.println("学生类的无参构造");
}
@Override
public String toString() {
return "学生类";
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化方法");
}
public void myInit(){
System.out.println("我自己定义的初始化方法");
}
}
<property name="name" value="张三"></property>
ClassPathXmlApplicationContext s1 = new ClassPathXmlApplicationContext("application.xml");
控制台输出:
学生类的无参构造
student的set方法
初始化方法
我自己定义的初始化方法
```
3.什么叫初始化操作
```
资源的初始化:网络 IO 数据库 ......
```
第三销毁阶段
DisposableBean接口
```java
//重写方法
@Override
public void destroy() throws Exception {
System.out.println("销毁方法");
}
ClassPathXmlApplicationContext s1 = new ClassPathXmlApplicationContext("application.xml");
s1.close();//关闭工厂执行销毁方法
```
自定义方法
1. 不适用于scope="prototype"
2. 什么叫销毁操作
```
主要是做一些资源的释放操作 io.close() connection.close();
```
总结:
Spring 容器可以管理 singleton 作用域下 bean 的生命周期,在此作用域下,Spring 能够精确地知道bean何时被创建,何时初始化完成,以及何时被销毁。而对于 prototype 作用域的bean,Spring只负责创建,当容器创建了 bean 的实例后,bean 的实例就交给了客户端的代码管理,Spring容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype作用域的bean的生命周期。
大体的三个阶段
- 实例化并属性赋值 Instantiation、Populate
- 初始化 Initialization
- 销毁 Destruction
回顾看下描述内容,结合代码再理解下,相信大家更加理解什么是Spring Bean的生命周期了吧!
记得点赞+关注哦~~