当前位置:   article > 正文

SpringBean生命周期和加载过程_bean加载过程和生命周期

bean加载过程和生命周期

SpringBean生命周期简单版

单例对象在加载Spring配置文件的时候就创建出来了,非单例对象在每一次使用的时候通过getBean创建。
容器关闭之前,调用bean的销毁方法。
实例化bean对象(通过工厂),设置对象属性(依赖注入),调用Bean的Id传入工厂,调用Bean的初始化方法,使用bean。
在这里插入图片描述

Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化。Bean实例化后对将Bean的引入和值注入到Bean的属性中
如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。实际应用
如果Bean实现了BeanPostProcessor接口,调用预初始化方法
如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调
如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法
此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁
如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用

SpringBean生命周期进阶版

参考1
参考2

主要

主要有这4个阶段:

1.实例化 Instantiation
2.属性赋值 Populate
3.初始化 Initialization
4.销毁 Destruction

时序图:
在这里插入图片描述

几个重要的接口和类:

BeanFactoryPostProcessor接口
InstantiationAwareBeanPostProcessor接口
BeanPostProcessor接口

AbstractAutowireCapableBeanFactory

实例化属性赋值对应构造方法setter方法注入,初始化和销毁是能自定义扩展的两个阶段。 主要逻辑都在AbstractAutowireCapableBeanFactorydoCreateBean()方法中。

首先来看AbstractAutowireCapableBeanFactory所处的位置
在这里插入图片描述
doCreateBean()方法逻辑很清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应

  1. createBeanInstance() -> 实例化
  2. populateBean() -> 属性赋值
  3. initializeBean() -> 初始化
   //  此代码忽略了一些无关代码
    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
      
        
        if (instanceWrapper == null) {
        //  实例化
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        try {
        	//   属性赋值
            this.populateBean(beanName, mbd, instanceWrapper);
            //   初始化
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }
        }
   
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

常用扩展点

Spring生命周期相关的常用扩展点非常多 ,

第一大类:Spring默认对Bean处理的接口(默认由Spring管理的bean都会被这些接口处理)

实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

这两父子可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。

在这里插入图片描述
InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口

InstantiationAwareBeanPostProcessor extends BeanPostProcessor
  • 1

在这里插入图片描述

第二大类:用于用户自定义扩展的接口(这类接口用于用户自定义扩展,只有bean实现这类接口,这些bean才会被这些接口操作)

这一大类接口的特点是功能丰富,常用于用户自定义扩展。
第二大类中又可以分为两类:

1. Aware类型的接口
2. 生命周期接口

Spring之所有有一堆Aware接口,主要为了给开发者留下嵌入点,在Bean的生命周期过程中做很多操作。
如下面两幅图在初始化阶段调用 Aware类型的接口
Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源,。Aware之前的名字就是可以拿到什么资源BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。例如BeanNameAware可以拿到BeanName

在这里插入图片描述

这里把Aware接口分为两组,因为调用
Aware Group1

BeanNameAware
BeanClassLoaderAware
BeanFactoryAware

Aware Group2

EnvironmentAware
EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口,如下:

Aware调用时机源码分析

详情如下,忽略了部分无关代码。代码位置就是我们上文提到的initializeBean方法详情,这也说明了Aware都是在初始化阶段之前调用的

 	// 见名知意,初始化阶段调用的方法
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

 		// 这里调用的是Group1中的三个Bean开头的Aware
        invokeAwareMethods(beanName, bean);

        Object wrappedBean = bean;
        
        // 这里调用的是Group2中的几个Aware,
        // 而实质上这里就是前面所说的BeanPostProcessor的调用点!
        // 也就是说与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的。
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        // 下文即将介绍的InitializingBean调用点
        invokeInitMethods(beanName, wrappedBean, mbd);
        // BeanPostProcessor的另一个调用点
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

        return wrappedBean;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这里插入图片描述

可以看到并不是所有的Aware接口都使用同样的方式调用。
Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。感兴趣的可以自己看一下ApplicationContextAwareProcessor这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。

BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。

两个简单的生命周期接口

至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。

InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。
有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式

DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。

总结

Spring Bean的生命周期分为四个阶段多个扩展点
扩展点又可以分为默认的Bean处理接口可以自定义的Bean拓展处理接口

四个阶段

实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction

多个扩展点

默认的Bean处理接口

BeanPostProcessor
InstantiationAwareBeanPostProcessor

可以自定义的Bean拓展处理接口

Aware

BeanNameAware
BeanClassLoaderAware
BeanFactoryAware

EnvironmentAware
EmbeddedValueResolverAware
ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)

生命周期

InitializingBean
DisposableBean

具体应用

参数校验功能中,使用过ApplicationContextAware来获取到ApplicationContext,使用ApplicationContext的方法
去看看

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/66377
推荐阅读
相关标签
  

闽ICP备14008679号