原创

Spring 获取Bean的流程(二)

一 、 ClassPathXmlApplicationContext 加载器的时序图

1.png

二、Spring Bean 的生命周期

2.png

三、源码分析

主要逻辑都在doCreate()方法中(context.getBean("designFactoryBean")时)
getBean(beanName) 这个方法经常用来从 BeanFactory 中获取一个 Bean,而初始化的过程也封装到了这个方法里。

3.1 实例化 Instantiation

// 实例化阶段!
instanceWrapper = createBeanInstance(beanName, mbd, args);

触点:在factoryBean 的 doCreateBean() 方法

3.1.1 InstantiationAwareBeanPostProcessor接口的前置方法 postProcessBeforeInstantiation()

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    ......
    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
    if (bean != null) {
       bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    }
    ......
}

postProcessBeforeInstantiation接口的Before在doCreateBean之前调用,也就是在bean实例化之前调用的,英文源码注释解释道该方法的返回值会替换原本的Bean作为代理,这也是Aop等功能实现的关键点。

3.1.2 实例化,执行bean的构造方法、@PostConstruct注解

createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)

执行顺序
Constructor构造方法 --> @PostConstruct注解标记的方法

3.2 populateBean() -> 属性赋值

// 属性赋值阶段!
populateBean(beanName, mbd, instanceWrapper);

3.2.1 InstantiationAwareBeanPostProcessor接口的后置方法 postProcessAfterInstantiation()

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    ......
   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;
            }
         }
      }
   }
   ......
}

3.3.2 属性赋值

3.3 initializeBean() -> 初始化

// 初始化阶段!
exposedObject = initializeBean(beanName, exposedObject, mbd);

3.3.1 Aware调用时机

无所不知的Aware。
Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   ......
   // 这里调用的是三个Bean开头的Aware: BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
   invokeAwareMethods(beanName, bean);
   ......

   // 这里调用的是EnvironmentAware、EmbeddedValueResolverAware、ApplicationContextAware
   // 借助 BeanPostProcessor#postProcessBeforeInitialization()实现的invokeAwareInterfaces。(ApplicationContextAwareProcessor)
   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   ......

   try {
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }

   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

3.3.2 BeanPostProcessor的postProcessBeforeInitialization方法

if (mbd == null || !mbd.isSynthetic()) {
   //如果其中某一个后置处理器返回为null,则后续的后置处理器将不再调用,而直接返回
   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

3.3.3 InitializingBean接口的afterPropertiesSet方法, 如果接口被实现

// invokeInitMethods方法中
((InitializingBean) bean).afterPropertiesSet()

3.3.4 xml中配置的 init-method ,或@Bean注解中配置的 initMethod 方法

// 调用自定义的init-method 方法(xml中配置的,或@Bean注解中配置的)
invokeCustomInitMethod(beanName, bean, mbd);

3.3.5 BeanPostProcessor 的postProcessAfterInitialization方法

if (mbd == null || !mbd.isSynthetic()) {
   //如果其中某一个后置处理器返回为null,则后续的后置处理器将不再调用,而直接返回
   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

3.4 消亡

在容器关闭时调用的,详见ConfigurableApplicationContext#close()

3.4.1 @PreDestroy注解标记的 或 DisposableBean 接口的destroy方法

以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法

3.4.2 @Bean注解的destroyMethod方法

执行顺序
@PreDestroy --> DisposableBean --> destroy-method

~ end

正文到此结束
广告是为了更好的提供数据服务
本文目录