秒懂SpringBoot之Spring对象生命周期与扩展点浅尝辄止
Posted ShuSheng007
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了秒懂SpringBoot之Spring对象生命周期与扩展点浅尝辄止相关的知识,希望对你有一定的参考价值。
[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007
文章目录
概述
IOC与AOP是Spring框架最重要的两个思想。其中的IOC使得我们可以将对象及其依赖交由Spring容器来管理,极大的解放了我们的生产力。但凡事都有两面性,我们在逃避义务的同时也就意味着放弃了控制的权利,以前对象和依赖都是由我们负责处理,我们想怎么弄就怎么弄,但现在交给了spring这个大兄弟,我们做了甩手掌柜,那我们就失去了控制的权利。幸好Spring这个大兄弟比较厚道,给我们留下了若干个扩展点,这些扩展点就是它给我们干预被托管对象的机会,所以我们一定要抓住。
这块经过广大码农兄弟们不懈的内卷已经产生了非常多特别靠谱的资料,各种源码解析一大堆了,可惜就是太绕,这篇文章也只是我自己梳理这个过程留下的笔记,不构成教学资料,不喜勿喷…
Bean的生命周期
你有没有想过在我们日常开发过程中,给类加个@Componet
然后用的时候来一个@Autowired
就搞定了,这背后发生了什么?总的来说呢就是你在启动App的时候Spring大兄弟先把这些被@Componet
的类给生成对象保存起来,然后你使用@Autowired
召唤的时候它就还给你。
咱今天看下Spring大兄弟是怎么把这些类给生成对象的,在不需要这些对象的时候是怎么给处理掉的,以及在这个过程中给我们提供了哪些观察和干预这个过程的机会。如果它不给我们干预的机会那就麻烦了,假如你有个需求:
程序员:hi,Spring大兄弟,我想在这个对象属性设置完成后打一句日志,你看行吗?
Spring:不好意思呀,俺不支持,你能不能自己想想办法…
程序员:我R…
首先,Spring大兄弟先把扫描到的要生成对象的类都给包装成BeanDefinition
,然后保存到BeanDefinitionRegistry
中,用的时候就从这个registry里面取。
感受Bean生命周期
让我们先来感受一下Bean的生命周期以及扩展点吧,学习这些开源框架一个非常好的思路为:会用–学习内部实现方式–善用–改进内部实现方式–提交PullRequest,大部分时候我们都止于第一步…
我写了一个实现各种Bean级别的扩展点的类,以及两个实现容器级别的扩展点的类,然后运行,查看日志。
Programmer
类实现了各种常用的Bean级别的扩展点
//@Component
public class Programmer implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean
private JavaLang javaLang;
public Programmer()
System.out.println("1.调用构造函数");
// @Autowired
public void setJavaLang(JavaLang javaLang)
System.out.println("2.调用属性赋值方法:" + javaLang.getClass().getCanonicalName());
this.javaLang = javaLang;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException
System.out.println("4.调用BeanFactoryAware扩展:" + beanFactory.getClass().getCanonicalName());
@Override
public void setBeanName(String name)
System.out.println("3.调用BeanNameAware扩展:" + name);
@Override
public void destroy() throws Exception
System.out.println("9.调用DisposableBean扩展");
@Override
public void afterPropertiesSet() throws Exception
System.out.println("7.调用InitializingBean扩展");
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
System.out.println("5.调用ApplicationContextAware扩展:" + applicationContext.getClass().getCanonicalName());
@PostConstruct
public void myInit()
System.out.println("6.调用@PostConstruct注解的方法");
@PreDestroy
public void myDestroy()
System.out.println("8.调用@PreDestroy注解的方法");
//在@Bean里使用
public void myInit2()
System.out.println("调用@Bean initMethod方法");
//在@Bean里使用
public void myDestroy2()
System.out.println("调用@Bean destroyMethod方法");
- 下面两个类实现了容器级别的扩展点
InstantiationAwareBeanPostProcessor
与BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 BeanPostProcessor.postProcessBeforeInitialization() 方法,bean:" +
bean.getClass().getCanonicalName());
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 BeanPostProcessor.postProcessAfterInitialization() 方法,bean:" +
bean.getClass().getCanonicalName());
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法,bean:" +
beanClass.getCanonicalName());
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法,bean:" +
bean.getClass().getCanonicalName());
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法,bean:" +
bean.getClass().getCanonicalName() +
" values:" + Arrays.toString(pvs.getPropertyValues()));
return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法,bean:" +
bean.getClass().getCanonicalName());
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
if ("programmer".equals(beanName))
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法,bean:" +
bean.getClass().getCanonicalName());
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
- Config文件
生成Programmer的Bean
@Configuration
public class LifecycleConfig
@Bean(name = "programmer", initMethod = "myInit2", destroyMethod = "myDestroy2")
public Programmer programmer()
Programmer programmer = new Programmer();
// 使用这句直接设置属性的代码,无法测试出spring bean 注入属性的那个步骤
programmer.setJavaLang(new JavaLang());
return programmer;
值得注意的是,直接调用设置对象属性的方法不能展现出spring设置属性的生命周期。 这块可以使用@Componet
以及使用@Autowired
的方式注入属性。 这里主要是为了调用@Bean
里的初始化与销毁的方法。
- 测试调用:
可以在close前面打断点观察
@SpringBootApplication
public class MvcInspectApplication
public static void main(String[] args)
ConfigurableApplicationContext applicationContext = SpringApplication.run(MvcInspectApplication.class, args);
Programmer programmer = (Programmer) applicationContext.getBean("programmer");
applicationContext.close();
输出:
调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
1.调用构造函数
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer values:[]
2.调用属性赋值方法:top.shusheng007.mvcinspect.beanlifecycle.JavaLang
3.调用BeanNameAware扩展:programmer
4.调用BeanFactoryAware扩展:org.springframework.beans.factory.support.DefaultListableBeanFactory
5.调用ApplicationContextAware扩展:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
调用 BeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
6.调用@PostConstruct注解的方法
7.调用InitializingBean扩展
调用@Bean initMethod方法
调用 BeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
8.调用@PreDestroy注解的方法
9.调用DisposableBean扩展
调用@Bean destroyMethod方法
具体说明
从输出已经可以看到这些扩展点的执行顺序了,其中混杂这两个容器级别的扩展点的输出。
Bean的生命周期可以大体分为下面四个步骤,上面的输出都可以归纳进这四个步骤中
- 实例化 Instantiation
根据BeanDefinition
通过反射来创建类的实例
调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
1.调用构造函数
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer values:[]
可见InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
在对象实例化之前被执行了。开那个类的名称前缀`InstantiationAware,一看就知道是感受对象实例化过程的。
- 属性赋值 Populate
给生成的对象设置属性,例如你经常使用的@Autowired
,@Value
什么的来设置类的属性。
2.调用属性赋值方法:top.shusheng007.mvcinspect.beanlifecycle.JavaLang
- 初始化 Initialization
处理各种Aware
接口回调,例如BeanNameAware
,以及那些初始化的方法,例如使用@PostConstruct
注解的方法,以及在@Bean
里面指定的初始化方法等。
3.调用BeanNameAware扩展:programmer
4.调用BeanFactoryAware扩展:org.springframework.beans.factory.support.DefaultListableBeanFactory
5.调用ApplicationContextAware扩展:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
调用 BeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
6.调用@PostConstruct注解的方法
7.调用InitializingBean扩展
调用@Bean initMethod方法
调用 BeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
- 销毁 Destruction
调用使用@PreDestroy
注解的方法,以及DisposableBean
接口的回调,还有在@Bean
里面指定的销毁方法等
8.调用@PreDestroy注解的方法
9.调用DisposableBean扩展
调用@Bean destroyMethod方法
整个Bean的产生逻辑中,前3个阶段的代码在AbstractAutowireCapableBeanFactory
类的doCreateBean
方法里,可自行查看。
可能是我水平不够吧,亦或者是框架比较复杂,我读的时间又比较短,看Spring的源码感觉真的是好乱啊,要想摸清楚,你还是要自己打断点跟一下,不过可能跟着跟着就跑偏了…
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException
// Instantiate the bean.
//第一步:实例化 Instantiation
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null)
instanceWrapper = createBeanInstance(beanName, mbd, args);
...
// Initialize the bean instance.
Object exposedObject = bean;
try
//第二步:属性赋值 Populate
populateBean(beanName, mbd, instanceWrapper);
//第三步:初始化 Initialization
exposedObject = initializeBean(beanName, exposedObject, mbd);
第四个销毁的阶段在AbstractApplicationContext
的doClose
方法里
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext
// 第四步:销毁 Destruction
protected void doClose()
上面就是Spring Bean 的生命周期概述了,其实这个生命周期4个阶段知道大概就行,我们特别关心的其实是Spring大兄弟给我们的各种扩展点,因为我们真的要用他们来写程序,不知道就没法写…下面让我们大概看一下
扩展点
所谓Bean生命周期的扩展点,就是Spring留给我们干预Bean生命周期的回调。这个比较好理解,因为我们把对象及其依赖的管理托管给了Spring,但是我们又要在这个过程中进行干预,所以spring就必须在管理Bean的各个阶段不断的询问我们:
hello: 死码农,现在俺正在对象的实例化阶段,你有什么要处理的吗?
hi: 屌丝,现在刚刚给对象设置完属性,你有什么要处理的吗?
哎:攻城狮,现在我要销毁对象拉,你丫有什么要处理的吗?
喂:那个谁,现在…,你要…?
扩展点分为容器级与对象级,如果是容器级的话你实现的那个扩展点操作会应用到容器内所有的Bean,如果是Bean级别的话就只能影响那个Bean。
容器级扩展点
容器级扩展点作用于整个容器,对容器内的bean都起作用
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
下面这张图是我从这里一文读懂 Spring Bean 的生命周期致敬的…。
图中展示了两个容器级别的扩展点在Bean生命周期的回调点。其实那几个回调方法的名称已经非常好的说明了他们执行的时机,在Bean实例化的前后,以及在bean初始化的前后都有回调点。
对象级扩展点
对象级扩展点作用于单个bean,只对单个bean起作用
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- EnvironmentAware
- EmbeddedValueResolverAware
- ApplicationContextAware
多一点
你想过SpringBoot程序启动后是怎么一路执行的吗?不怕你笑话,我以前想过,但没想明白,这肯定想不明白啊,得看…
- 入口
SpringApplication
类的静态run
方法
@SpringBootApplication
public class MvcInspectApplication
public static void main(String[] args)
SpringApplication.run(MvcInspectApplication.class, args);
- 具体执行方法
SpringApplication
类的
public ConfigurableApplicationContext run(String... args)
//打印Spring的标志
Banner printedBanner = printBanner(environment);
//开始处理Bean的流程
refreshContext(context);
- AbstractApplicationContext
refreshContext(context);
调用到了AbstractApplicationContext
的refresh
方法,老重要了…
public void refresh() throws BeansException, IllegalStateException
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
finishBeanFactoryInitialization(beanFactory);
这个方法就是处理Bean的入口。
- AbstractAutowireCapableBeanFactory
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException
// Instantiate the bean.
//第一步:实例化 Instantiation
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null)
instanceWrapper = createBeanInstance(beanName, mbd, args);
...
// Initialize the bean instance.
Object exposedObject = bean;
try
//第二步:属性赋值 Populate
populateBean(beanName, mbd, instanceWrapper);
//第三步:初始化 Initialization
exposedObject = initializeBean(beanName, exposedObject, mbd);
总结
读完本文至少要明白,扩展点分两类,Bean生命周期分4步,几个关键扩展点执行时机。
一如既往的你可以从GitHub上获得源码 mvc-inspect
好文推荐:
以上是关于秒懂SpringBoot之Spring对象生命周期与扩展点浅尝辄止的主要内容,如果未能解决你的问题,请参考以下文章
秒懂SpringBoot之全网最易懂的Spring Security教程
java版Spring Cloud+SpringBoot+mybatis+uniapp b2b2c 之分析商品管理强化商品互联网特性及线上商品生命周期管理