Spring Bean的生命周期(一) - 概述

1. 如何全面理解bean的生命周期

img

如果这只是一个普通的 java 的对象,那这个图示完全成立、合理。不过在 SpringFramework 中,这个流程就不够完整了,我们来回忆一下前面学习的内容。

1.1 bean的创建之前

在 bean 的创建之前,bean 是以 BeanDefinition 的方式被描述和注册在 BeanFactory 的(准确的说是注册在 BeanDefinitionRegistry 中),这个时候虽然 bean 还没有被创建,但是 BeanFactory 中已经存有 bean 对应的 BeanDefinition 了,所以在 bean 的实例化之前,还应该有 **BeanDefinition** 阶段

1.2 BeanDefinition的由来

BeanDefinition 也不是凭空出现的,要么是解析了配置文件(比如xml),要么是解析了配置类(比如@Configuration),要么有人编程式(注解)的注入了 BeanDefinition ,所以如果纵观整个 bean 的生命周期,在 BeanDefinition 阶段之前,还应该有 BeanDefinition 的来源和加载阶段。

2. BeanDefinition阶段的主要工作

2.1 BeanDefinition的来源

上面咱也说了,bean 的实例化需要先有 BeanDefinition 的信息,所以 BeanDefinition 都是怎么来的呢?这里我们来理一下。

  • 声明式注入 BeanDefinition

    • @Configuration + @Bean

@Configuration
public class QuickStartConfiguration {
    @Bean
    public Person person() {
        return new Person();
    }
}
    • @Component + @ComponentScan

@Configuration
@ComponentScan("com.linkedbear.spring.annotation.c_scan")
public class ComponentScanConfiguration
    • @Import

@Import({Boss.class, BartenderConfiguration.class})
public @interface EnableTavern
  • 配置式注入 BeanDefinition

    • <bean> 标签声明

<bean id="person" class="com.linkedbear.spring.basic_dl.a_quickstart_byname.bean.Person"/>
  • 编程式注入 BeanDefinition

    • ImportBeanDefinitionRegistrar

public class WaiterRegistrar implements ImportBeanDefinitionRegistrar {
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        registry.registerBeanDefinition("waiter", new RootBeanDefinition(Waiter.class));
    }
}
    • 手动构造 BeanDefinition 注入

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

BeanDefinition personDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class)
  .addPropertyValue("name", "zhangsan").getBeanDefinition();
ctx.registerBeanDefinition("person", personDefinition);

ctx.refresh();
    • 借助 BeanDefinitionRegistryPostProcessor 注入

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    registry.registerBeanDefinition("animalNameSetterPostProcessor", 
            new RootBeanDefinition(AnimalNameSetterPostProcessor.class));
}

通过上述的方式,就可以把 BeanDefinition 注入到 BeanFactory 中了。

2.2 BeanDefinition的后置处理

根据前面后置处理器学过的内容,我们可以知道 BeanDefinition 都构造好之后,是不会立即注册到 BeanFactory 的,这中间有一步执行 BeanDefinitionRegistryPostProcessor 的动作,等这些 BeanDefinitionRegistryPostProcessor 都执行完 postProcessBeanDefinitionRegistry 方法后,BeanDefinition 才会注册到 BeanFactory

img

这个动作之后,下一步则是执行 BeanFactoryPostProcessorpostProcessBeanFactory 方法了,这个阶段可以给 BeanDefinition 修改配置信息,添加注入的依赖项,给属性赋值等操作。

img

这一步执行完毕后,BeanDefinition 就不会再动了,BeanDefinition 的阶段也就算结束了。

3. bean实例阶段的内容

AbstractApplicationContextrefresh 方法中找到执行步骤,其中第 11 步 finishBeanFactoryInitialization 方法就是初始化 bean 实例的动作了:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        
        try {
            postProcessBeanFactory(beanFactory);
            invokeBeanFactoryPostProcessors(beanFactory);
            registerBeanPostProcessors(beanFactory);
            initMessageSource();
            initApplicationEventMulticaster();
            onRefresh();
            registerListeners();
            // 11. 初始化剩余的单实例bean
            finishBeanFactoryInitialization(beanFactory);
            finishRefresh();
        }
        // catch ......
        finally {
            resetCommonCaches();
        }
    }
}

这一步的动作非常多,它会将所有还没有实例化的、非延迟加载的单实例 bean 都创建出来。而创建一个 bean 的流程也是非常多且复杂,总体可以分为以下几个步骤。

3.1 BeanDefinition的合并

bean 的实例化阶段,第一步并不是直接创建对象,还记得之前的 BeanDefinition 合并那个特性吗?如果一个 <bean> 有继承另外一个 <bean> 定义,则会形成父子定义。这种情况下,创建 bean 的时候就需要读取父 bean 的定义,合并为最终的 RootBeanDefinition

3.2 bean的实例化

合并完 BeanDefinition ,下一步才是真正的实例化 bean ,不过这里要注意一个问题:如果 bean 是一个 FactoryBean ,这里该如何处理呢?是只创建 FactoryBean 本身?还是连 FactoryBean 创建的真实对象一起创建?

除了考虑 FactoryBean 之外,还有一个要考虑的因素是缓存问题。咱在一开始学 IOC 的由来时,就知道 BeanFactory 中可以缓存单实例 bean ,那么在 Spring 中是如何处理单实例 bean 在实例化后的缓存呢?

3.3 属性赋值+依赖注入

bean 对象实例化完成后,里面所有的成员都是空的,接下来的步骤就是属性赋值和依赖注入了。由于这部分逻辑属于 bean 实例已经创建,所以小册在这里将该步骤划到下面的 bean 初始化部分

在这个环节,最重要的是如何处理 <bean> 中的 <property> 标签、bean 中的 @Value@Autowired 等自动注入的注解。

BeanPostProcessor 的扩展 InstantiationAwareBeanPostProcessor 可以在 bean 的实例化之后、初始化之前执行 postProcessAfterInstantiation 方法,以及 postProcessProperties ( postProcessPropertyValues ) 方法完成属性赋值!所以我们就可以断定,这个环节一定是 InstantiationAwareBeanPostProcessor 在工作。

3.4 bean的初始化

这个阶段相信小伙伴们都非常熟悉了,这部分就不多啰嗦了吧,后面直接翻源码看看底层原理就完事了。

3.5 bean的启动

之前在 bean 的生命周期中没有提到一个接口:Lifecycle ,之所以没有在那儿提,是考虑到 Lifecycle 的执行是依照 ApplicationContext 的生命周期而来,两者是相互关联的,所以小册把 Lifecycle 接口的讲解安排到了这里。

先简单说说 Lifecycle 的触发时机吧。往上翻一翻 refresh 方法的 try 块最后一行:finishRefresh ,它在里面会找出所有实现了 Lifecycle 接口的 bean ,并调用它们的 start 方法(所以是不是回想起了第 16 章的 ContextStartedEvent 事件)。注意此时所有实现了 Lifecycle 的非延迟加载的单实例 bean 都已经加载完成了,是可以正常调用 start 方法的。

一般实现 Lifecyclestart 方法多用于建立连接加载资源等等操作,以备程序的运行期使用。

so ,这个阶段 ApplicationContext 就会完成所有 Lifecycle 类型的 bean 的 start 方法调用,对于一个 bean 的生命周期而言,就已经到了正常存活期了。


说完了 bean 的加载和初始化,当 ApplicationContext 关闭时,这些 bean 也是需要销毁的,而这个销毁流程我们也要来研究一下。

4. bean销毁阶段的内容

相比较于 bean 的创建和初始化,销毁部分就变得比较简单了,我们可以先对整个 ApplicationContext 的关闭有一个整体的了解。

关闭 ApplicationContext 会顺序执行以下几步:

  1. 广播容器关闭事件

    • 学过的 ContextClosedEvent 事件

  1. 通知所有实现了 Lifecycle 的 bean 回调 close 方法

  2. 销毁所有 bean

  3. 关闭 BeanFactory

  4. 标记本身为不可用,

而这里面有关 bean 的销毁,就只包含 2 、3 两步,下面分述。

4.1 bean的停止

与上面的 bean 启动一致,如果一个 bean 实现了 Lifecycle 接口,此处会回调 bean 的 close 方法。由于此时 bean 的销毁回调方法还没有执行,所以在销毁阶段,Lifecycle 的执行时机是最靠前的。

一般实现 Lifecycleclose 方法多用来关闭连接、释放资源等操作,因为程序终止了,这些资源也就没必要持有了。

4.2 bean的销毁回调

bean “停止” 后,接下来就是对应于 bean 初始化阶段的三种生命周期回调的销毁部分了。不过这里面有一个不同点:BeanPostProcessor 的回调包含 bean 的初始化之前和初始化之后,但 DestructionAwareBeanPostProcessor 只包含 bean 销毁回调之前的动作,没有之后。

最后更新于

这有帮助吗?