Spring中Bean的生命周期是Spring面试的热点问题。这个问题既考察对Spring的微观了解,又考察对Spring的宏观认识。如果在面试中能回答出来,肯定会给面试官留下比较深刻的印象。本文我们就一起来看一下Spring中Bean加载的核心流程。
1. Spring中bean的核心加载流程
在传统的Java应用中,一个对象的生命周期很简单,new 出来之后进行实例化,然后这个对象就可以使用了,一旦后面我们不再使用这个对象了,JVM就会自动进行垃圾回收。
相比之下,Spring管理对象的生命周期就复杂多了,正确理解Spring的生命周期很重要,因为Spring对Bean的管理可扩展性非常强,下图展示在Spring中一个Bean产生的核心过程:
文字解释:
1、Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化、
2、Bean实例化后对将Bean的引入和值注入到Bean的属性中
3、如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
4、如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
5、如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来
6、如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
7、如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
8、如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
9、此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
10、如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用
上面的这些加载流程,如果能说出来,就已经完全足够应对面试了,所以,就算背也要背下来!!
2. 验证加载流程
为了加深印象,我们再用代码做一遍验证,看下Spring项目启动的时候,加载顺序是不是这样的。
创建一个Student类,实现Spring中的各个扩展点接口
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private String name;
public Student(){
System.out.println("Student 构造方法执行 ");
}
@Override
public void setBeanName(String name) {
System.out.println("Student#setBeanName() 执行");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Student#setBeanFactory() 执行");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Student#setApplicationContext() 执行");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Student#afterPropertiesSet() 执行");
}
@Override
public void destroy() throws Exception {
System.out.println("Student#destroy() 销毁方法执行");
}
public void setName(String name) {
this.name = name;
System.out.println("Student#setStudentName() 执行");
}
// 默认初始化方法
private void myPostConstruct() {
System.out.println("Student#myPostConstruct() 执行");
}
// 自定义初始化方法
@PostConstruct
public void springPostConstruct(){
System.out.println("@PostConstruct 自定义初始化方法执行");
}
//默认销毁方法
private void myPreDestroy() {
System.out.println("Student#myPreDestroy 执行");
}
//自定义销毁方法
@PreDestroy
public void springPreDestroy(){
System.out.println("@PreDestroy自定义销毁方法执行");
}
}
创建MyBeanPostProcessor,实现BeanPostProcessor接口
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Student){
System.out.println("MyBeanPostProcessor#postProcessBeforeInitialization()");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Student){
System.out.println("MyBeanPostProcessor#postProcessAfterInitialization()");
}
return bean;
}
}
创建配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
//指定默认初始化方法和默认销毁方法
@Bean(initMethod = "myPostConstruct",destroyMethod = "myPreDestroy")
public Student student(){
return new Student();
}
}
创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
启动SpringBoot项目,看到控制台打印结果
关闭SpringBoot项目,控制台打印销毁信息
从图中可以看出,Spring在启动过程中的加载顺序和我们上面说的顺序是一致的,可能有些小伙伴觉得这么多步骤,记起来太难了,其实我们可以把这些步骤做个简单的划分。
整体来看就四个阶段:
-
实例化阶段,就是先把这个对象new 出来
-
属性赋值,给这个对象中的属性赋值
-
初始化,看看有没有实现一些Aware接口,或者有没有BeanPostProcessor的前置后置处理,还有一些自定义的初始化方法。
-
销毁,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。