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整个生命周期,从初始化到销毁,本节将结合例子对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();
}}
日志打印结果如下所示。
文章图片
上述日志打印可以得出创建对象时类属性和对象属性的初始化顺序,如下所示。
文章图片
可以概括如下。
- 创建对象时,会先加载并初始化类;
- 如果类的父类未初始化,则会先初始化父类,再初始化子类;
- 初始化类时,先为静态变量赋初值,然后执行类的静态代码块;
- 类初始化后,会先初始化父类对象,然后再初始化子类对象;
- 初始化对象时,先为对象变量赋初值,然后执行类的普通代码块,最后执行构造方法。
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
的对象加载到容器中并开始管理其生命周期,日志打印如下所示。文章图片
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"));
}}
运行测试代码,日志打印如下所示。
文章图片
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.");
}}
运行测试代码,日志打印如下。
文章图片
bean实现了
ApplicationContextAware
接口就可以通过setApplicationContext()
方法获取到ApplicationContext
,从而通过ApplicationContext
获取Spring容器中的bean,setApplicationContext()
方法的调用时机在setBeanFactory()
方法之后。五. BeanPostProcessor
在二到四小节中分析的接口均只能针对实现了接口的bean执行一些操作,如果需要对Spring容器中的所有bean执行一些操作,则需要提供一个
BeanPostProcessor
接口的实现类。BeanPostProcessor
接口类图如下所示。文章图片
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();
}}
执行测试代码,日志打印如下。
文章图片
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.");
}}
运行测试代码,日志打印如下。
文章图片
可以知道
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();
}}
执行测试代码,日志打印如下所示。
文章图片
可知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();
}}
运行测试代码,日志打印如下。
文章图片
可知
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();
}}
执行测试代码,日志打印如下。
文章图片
可知bean自定义销毁方法的执行时机在
destroy()
方法之后。总结 【Spring-Bean的生命周期】Spring容器会负责容器内部的bean从创建到销毁。实现
BeanNameAware
接口的bean可以获取到bean在容器中的名字;实现BeanFactoryAware
接口的bean可以获取到BeanFactory
的引用;实现ApplicationContextAware
接口的bean可以获取到ApplicationContext
的引用;实现InitializingBean
接口的bean可以在bean初始化之后做一些操作;实现DisposableBean
接口的bean可以在bean销毁之前做一些事情。除此之外,可以定义BeanPostProcessor
接口的实现类,其重写的方法会作用于容器中的每个bean。推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量