秒懂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方法");
    


  • 下面两个类实现了容器级别的扩展点InstantiationAwareBeanPostProcessorBeanPostProcessor
@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);
		
	

第四个销毁的阶段在AbstractApplicationContextdoClose方法里

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); 调用到了AbstractApplicationContextrefresh方法,老重要了…

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

好文推荐:

请别再问Spring Bean的生命周期了!

以上是关于秒懂SpringBoot之Spring对象生命周期与扩展点浅尝辄止的主要内容,如果未能解决你的问题,请参考以下文章

Spring之Bean的生命周期详解

秒懂SpringBoot之全网最易懂的Spring Security教程

Spring之Bean的作用域与生命周期

java版Spring Cloud+SpringBoot+mybatis+uniapp b2b2c 之分析商品管理强化商品互联网特性及线上商品生命周期管理

重学SpringBoot系列之生命周期内的拦截过滤与监听

Spring知识点总结之Spring IOC