Spring-Bean的生命周期

前言 Spring中的bean都生存于Spring容器中,Spring容器负责初始化bean,装配bean和管理bean的生命周期。
Spring中的容器有两种。第一种是BeanFactory(org.springframework.beans.factory.BeanFactory),这是最简单的容器,提供基本的依赖注入功能;第二种是应用上下文ApplicationContext(org.springframework.context.ApplicationContext),基于BeanFactory创建,提供应用框架级别的服务。
本篇文章将结合读书时期的一篇Spring学习笔记,重新温习Spring容器对bean的生命周期管理。
Spring版本:5.3.2
Springboot版本:2.4.1
正文 Spring的bean生命周期可以用下图进行概括。
Spring-Bean的生命周期
文章图片

Spring会负责bean整个生命周期,从初始化到销毁,本节将结合例子对bean的生命周期进行演示和说明,全篇不会涉及Spring源码和Springboot源码。演示工程的搭建只需要创建Maven工程并引入如下依赖。

org.springframework.boot spring-boot-starter-web 2.4.1 org.projectlombok lombok 1.18.16 true

一. bean的初始化
bean的创建就是调用bean的构造方法将bean创建出来,本小节主要复习一个基础知识,即创建对象时类属性和对象属性的初始化顺序。
创建TestParentService,如下所示。
@Slf4j public class TestParentService {private static String parentStaticVariable = "INIT PARENT STATIC VARIABLE"; private String parenObjectVariable = "INIT PARENT OBJECT VARIABLE"; static { log.info("parentStaticVariable is " + parentStaticVariable); parentStaticVariable = "PARENT STATIC VARIABLE"; log.info("parentStaticVariable is " + parentStaticVariable); }{ log.info("parenObjectVariable is " + parenObjectVariable); parenObjectVariable = "PARENT OBJECT VARIABLE"; log.info("parenObjectVariable is " + parenObjectVariable); }public TestParentService() { log.info("TestParentService construction method execute."); }}

再创建TestSonService并继承TestParentService,如下所示。
@Slf4j public class TestSonService extends TestParentService {private static String sonStaticVariable = "INIT SON STATIC VARIABLE"; private String sonObjectVariable = "INIT SON OBJECT VARIABLE"; static { log.info("sonStaticVariable is " + sonStaticVariable); sonStaticVariable = "SON STATIC VARIABLE"; log.info("sonStaticVariable is " + sonStaticVariable); }{ log.info("sonObjectVariable is " + sonObjectVariable); sonObjectVariable = "SON OBJECT VARIABLE"; log.info("sonObjectVariable is " + sonObjectVariable); }public TestSonService() { log.info("TestSonService construction method execute."); }}

在测试程序中创建一个TestSonService的对象,并观察日志打印,测试代码如下所示。
public class TestClient {public static void main(String[] args) { TestSonService testSonService = new TestSonService(); }}

日志打印结果如下所示。
Spring-Bean的生命周期
文章图片

上述日志打印可以得出创建对象时类属性和对象属性的初始化顺序,如下所示。
Spring-Bean的生命周期
文章图片

可以概括如下。
  • 创建对象时,会先加载并初始化类;
  • 如果类的父类未初始化,则会先初始化父类,再初始化子类;
  • 初始化类时,先为静态变量赋初值,然后执行类的静态代码块;
  • 类初始化后,会先初始化父类对象,然后再初始化子类对象;
  • 初始化对象时,先为对象变量赋初值,然后执行类的普通代码块,最后执行构造方法。
二. BeanNameAware
bean通过实现BeanNameAware接口可以获取bean在容器中的名字。定义一个TestService,并实现BeanNameAware接口,如下所示。
@Slf4j public class TestService implements BeanNameAware {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }}

基于JavaConfig的方式将TestService的对象注册为容器中的bean,配置类BeanConfig如下所示。
@Configuration public class BeanConfig {@Bean public TestService testService() { return new TestService(); }}

测试代码如下所示。
public class TestClient {public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); }}

创建Spring容器时就会将TestService的对象加载到容器中并开始管理其生命周期,日志打印如下所示。
Spring-Bean的生命周期
文章图片

bean实现了BeanNameAware接口就可以通过setBeanName()方法获取到bean在容器中的名字,并且setBeanName()方法的调用时机在创建bean之后。
三. BeanFactoryAware
实现了BeanFactoryAware接口的bean,可以获取到BeanFactory的引用。修改TestService并让其实现BeanFactoryAware接口,如下所示。
@Slf4j public class TestService implements BeanNameAware, BeanFactoryAware {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("testService is a singleton bean = " + beanFactory.isSingleton("testService")); }}

运行测试代码,日志打印如下所示。
Spring-Bean的生命周期
文章图片

bean实现了BeanFactoryAware接口就可以通过setBeanFactory()方法获取到BeanFactory,从而可以实现判断bean的作用域等功能,setBeanFactory()方法的调用时机在setBeanName()方法之后。
四. ApplicationContextAware
实现了ApplicationContextAware接口的bean,可以获取到ApplicationContext的引用,通常可以通过ApplicationContext来获取Spring容器管理的bean。修改TestService并让其实现ApplicationContextAware接口,如下所示。
@Slf4j public class TestService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("testService is a singleton bean = " + beanFactory.isSingleton("testService")); }@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("setApplicationContext method execute."); }}

运行测试代码,日志打印如下。
Spring-Bean的生命周期
文章图片

bean实现了ApplicationContextAware接口就可以通过setApplicationContext()方法获取到ApplicationContext,从而通过ApplicationContext获取Spring容器中的bean,setApplicationContext()方法的调用时机在setBeanFactory()方法之后。
五. BeanPostProcessor
在二到四小节中分析的接口均只能针对实现了接口的bean执行一些操作,如果需要对Spring容器中的所有bean执行一些操作,则需要提供一个BeanPostProcessor接口的实现类。BeanPostProcessor接口类图如下所示。
Spring-Bean的生命周期
文章图片

BeanPostProcessor接口定义了两个default方法,BeanPostProcessor接口的实现类可以选择对其进行重写以实现特定的业务逻辑。定义DecoratorService类并实现BeanPostProcessor接口,如下所示。
@Slf4j public class DecoratorService implements BeanPostProcessor {@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof TestService) { log.info("postProcessBeforeInitialization method execute."); } return bean; }@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof TestService) { log.info("postProcessAfterInitialization method execute."); } return bean; }}

修改BeanConfig,将DecoratorService的对象添加到Spring容器中,如下所示。
@Configuration public class BeanConfig {@Bean public TestService testService() { return new TestService(); }@Bean public DecoratorService decoratorService() { return new DecoratorService(); }}

执行测试代码,日志打印如下。
Spring-Bean的生命周期
文章图片

BeanPostProcessor接口的实现类重写的postProcessBeforeInitialization()方法会在setApplicationContext()方法之后执行,postProcessAfterInitialization()方法会在bean自定义的初始化方法之后执行。
六. InitializingBean
实现了InitializingBean接口的bean,可以在实现的afterPropertiesSet()方法中执行一些初始化逻辑。修改TestService并使其实现InitializingBean接口,如下所示。
@Slf4j public class TestService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("testService is a singleton bean = " + beanFactory.isSingleton("testService")); }@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("setApplicationContext method execute."); }@Override public void afterPropertiesSet() { log.info("afterPropertiesSet method execute."); }}

运行测试代码,日志打印如下。
Spring-Bean的生命周期
文章图片

可以知道afterPropertiesSet()方法的执行时机在postProcessBeforeInitialization()方法之后。
七. bean的自定义初始化方法
可以在类中自定义初始化方法,并在将对象注册到容器中时指定bean的自定义初始化方法。TestService修改如下所示。
@Slf4j public class TestService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("testService is a singleton bean = " + beanFactory.isSingleton("testService")); }@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("setApplicationContext method execute."); }@Override public void afterPropertiesSet() { log.info("afterPropertiesSet method execute."); }public void initBean() { log.info("initial method execute."); }}

修改BeanConfig如下所示。
@Configuration public class BeanConfig {@Bean(initMethod = "initBean") public TestService testService() { return new TestService(); }@Bean public DecoratorService decoratorService() { return new DecoratorService(); }}

执行测试代码,日志打印如下所示。
Spring-Bean的生命周期
文章图片

可知bean自定义初始化方法的执行时机在afterPropertiesSet()方法之后。
八. DisposableBean
实现了DisposableBean接口的bean可以在bean销毁前执行一些操作。修改TestService并实现DisposableBean接口,如下所示。
@Slf4j public class TestService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("testService is a singleton bean = " + beanFactory.isSingleton("testService")); }@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("setApplicationContext method execute."); }@Override public void afterPropertiesSet() { log.info("afterPropertiesSet method execute."); }public void initBean() { log.info("initial method execute."); }@Override public void destroy() { log.info("destroy method execute."); }}

修改测试代码,如下所示。
public class TestClient {public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class); //关闭容器,销毁bean applicationContext.close(); }}

运行测试代码,日志打印如下。
Spring-Bean的生命周期
文章图片

可知destroy()方法的调用时机在postProcessAfterInitialization()方法之后。
九. bean的自定义销毁方法
可以在类中自定义销毁方法,并在将对象注册到容器中时指定bean的自定义销毁方法。TestService修改如下所示。
@Slf4j public class TestService implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {private static String staticVariable = "INIT STATIC VARIABLE"; private String objectVariable = "INIT OBJECT VARIABLE"; static { log.info("staticVariable is " + staticVariable); staticVariable = "STATIC VARIABLE"; log.info("staticVariable is " + staticVariable); }{ log.info("objectVariable is " + objectVariable); objectVariable = "OBJECT VARIABLE"; log.info("objectVariable is " + objectVariable); }public TestService() { log.info("TestService construction method execute."); }@Override public void setBeanName(String name) { log.info("Bean name defined in context = " + name); }@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("testService is a singleton bean = " + beanFactory.isSingleton("testService")); }@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("setApplicationContext method execute."); }@Override public void afterPropertiesSet() { log.info("afterPropertiesSet method execute."); }public void initBean() { log.info("initial method execute."); }@Override public void destroy() { log.info("destroy method execute."); }public void destroyBean() { log.info("destroy bean method execute."); }}

修改BeanConfig,如下所示。
@Configuration public class BeanConfig {@Bean(initMethod = "initBean", destroyMethod = "destroyBean") public TestService testService() { return new TestService(); }@Bean public DecoratorService decoratorService() { return new DecoratorService(); }}

执行测试代码,日志打印如下。
Spring-Bean的生命周期
文章图片

可知bean自定义销毁方法的执行时机在destroy()方法之后。
总结 【Spring-Bean的生命周期】Spring容器会负责容器内部的bean从创建到销毁。实现BeanNameAware接口的bean可以获取到bean在容器中的名字;实现BeanFactoryAware接口的bean可以获取到BeanFactory的引用;实现ApplicationContextAware接口的bean可以获取到ApplicationContext的引用;实现InitializingBean接口的bean可以在bean初始化之后做一些操作;实现DisposableBean接口的bean可以在bean销毁之前做一些事情。除此之外,可以定义BeanPostProcessor接口的实现类,其重写的方法会作用于容器中的每个bean。

    推荐阅读