1. 前言
Spring的核心特性就是控制反转(IOC)和切面编程(AOP),Spring通过IOC容器来实现这些特性,IOC容器中,用户定义的对象以Bean的形式存放,然后由Spring解决Bean之间的依赖关系,并且对Bean进行代理从而实现AOP编程。Spring中的Bean由BeanFactory生产,生产流程比较复杂,因为在生产过程中需要解决Bean之间的依赖、Bean的作用域、Bean的实例化前后处理、Bean的初始化前后处理等步骤,最后才能得到一个装配完全的Bean。本文的重点就是讲述一下Bean的生产流程,其中涉及到的BeanFactory、BeanPostProcessor等概念不做详细介绍。 Spring的Bean生产流程中的关键环节如下图所示:
2. 生产Bean的主要步骤
Spring生产Bean的过程就是将Spring中的Bean定义转为对应SpringBean实体,关于SpringBean定义我会在其它博客中详细介绍,Bean定义会在Spring容器启动的最初环节通过xml定义文件或者扫描注解注册到容器的缓存中,那么Spring的Bean定义是在什么时候转为Bean的实体的呢?通常是在调用容器的getBean方法的时候进行实例化的,比如Spring容器启动最后环境会通过getBean初始化所有的非懒加载的单例Bean。那么Spring的getBean流程生怎么样的,内部是怎么样工作的呢?Spring getBean方法的流程主要有以下步骤:
- 校验BeanFactory的状态是激活状态,比如在@PreDestory中方法中调用getBean,这个时候容器已经处于销毁环节,会销毁容器中的Bean,这个时候再getBean会有并发问题,因此需要抛出异常,下面为校验容器状态的源码(部分容器不需要校验状态,如可重复Refresh的容器)。
protected void assertBeanFactoryActive() {
if (!this.active.get()) {
if (this.closed.get()) {
throw new IllegalStateException(getDisplayName() + " has been closed already");
}
else {
throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");
}
}
}
- 解析Bean的名称,Spring中,每个Bean的定义都有一个唯一的名称,同时有很多别名,我们在getBean的时候,可以安装别名、Bean名称和Bean的类来获取Bean,三种类型的参数最终都需要转为Bean的名称才能进行getBean的下一步。
- 单例模式解决循环依赖的缓存模型,Spring通过三级缓存解决单例Bean的循环依赖问题,其它作用域的Bean不允许出现循环依赖,否则会抛出异常。
- 双亲委派模型,Spring的容器之间允许有父子继承关系,子容器在getBean的环节会先把需要加载的Bean委托给父类加载,父类加载失败再由子类加载,类似于java的类加载模型,所以此处起名叫双亲委派模型。
- Bean定义的合并,Spring的Bean定义也允许有父子继承关系,在创建Bean的时候需要将父子Bean的定义合并为一个Bean,方便后续创建Bean
- Bean的实例化和初始化,这个阶段包含反射生成bean,并调用实例化前置后置处理方法、BeanPostProcessor方法、自动装配和初始化方法等。
3. Bean名称的解析
前文中我们说过,Spring在getBean的第一步必须要获取到Bean的名称,而Spring的getBean方法可以有三种类型的参数:Bean的别名、Bean的名称和Bean的类型,其中Bean的名称不需要进一步解析,但是Bean的别名和Bean的类型都需要解析为Bean的名称才能继续往下走。本节的重点内容就是Bean别名、工厂Bean和Bean类型解析为Bean的名称的过程。