美文网首页
Bean的生命周期

Bean的生命周期

作者: HannahLi_9f1c | 来源:发表于2021-01-26 16:06 被阅读0次

    一、Spring的四个阶段


    image.png
    1. 实例化 构造函数-》createBeanInstance
    2. 属性注入 setter-》populateBean
    3. 初始化 -》initializeBean
    4. 销毁
    // 忽略了无关代码
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
          throws BeanCreationException {
    
       // Instantiate the bean.
       BeanWrapper instanceWrapper = null;
       if (instanceWrapper == null) {
           // 实例化阶段!
          instanceWrapper = createBeanInstance(beanName, mbd, args);
       }
    
       // Initialize the bean instance.
       Object exposedObject = bean;
       try {
           // 属性赋值阶段!
          populateBean(beanName, mbd, instanceWrapper);
           // 初始化阶段!
          exposedObject = initializeBean(beanName, exposedObject, mbd);
       }
    
       }
    

    二、扩展点


    image.png

    实现了InstationAwareBeanProcessor方法的类,会在实例化前后调用postProcessBeforeInstantiation和postProcessAfterInstantiation方法,

    • postProcessBeforeInstantiation调用点如下:
    @Override
        protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                throws BeanCreationException {
    
            try {
                // postProcessBeforeInstantiation方法调用点,、,
                // 有兴趣的同学可以自己看下,就是for循环调用所有的InstantiationAwareBeanPostProcessor
                Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
                if (bean != null) {
                    return bean;
                }
            }
            
            try {   
                // 上文提到的doCreateBean方法,可以看到
                // postProcessBeforeInstantiation方法在创建Bean之前调用
                Object beanInstance = doCreateBean(beanName, mbdToUse, args);
                if (logger.isTraceEnabled()) {
                    logger.trace("Finished creating instance of bean '" + beanName + "'");
                }
                return beanInstance;
            }
            
        }
    
    • postProcessAfterInstantiation调用点
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    
       // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
       // state of the bean before properties are set. This can be used, for example,
       // to support styles of field injection.
       boolean continueWithPropertyPopulation = true;
        // InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
        // 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
       if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
          for (BeanPostProcessor bp : getBeanPostProcessors()) {
             if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                   continueWithPropertyPopulation = false;
                   break;
                }
             }
          }
       }
    
       // 忽略后续的属性赋值操作代码
    }
    

    可以看到该方法在属性赋值方法内,但是在真正执行赋值操作之前。其返回值为boolean,返回false时可以阻断属性赋值阶段(continueWithPropertyPopulation = false;)

    • 关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor在初始化前后调用就可以了
      三、无所不知的Aware
      Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。
      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;
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            // 下文即将介绍的InitializingBean调用点
            invokeInitMethods(beanName, wrappedBean, mbd);
            // BeanPostProcessor的另一个调用点
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    
            return wrappedBean;
        }
    

    可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。感

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

    关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个Aware方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。

    四、简单的两个生命周期接口
    至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。
    InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。
    有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
    除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。
    DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。感兴趣的可以自行跟一下源码。

    作者:sunshujie1990
    链接:https://www.jianshu.com/p/1dec08d290c1
    https://www.cnblogs.com/zrtqsk/p/3735273.html
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

          本文标题:Bean的生命周期

          本文链接:https://www.haomeiwen.com/subject/pfvgzktx.html