2.2.2 Bean的实例化
请注意,到现在为止,Spring IoC容器对Bean的创建过程并没有完成,我们只是将Bean的定义加载到了容器中而已。但是容器本身可能已经存在这些Bean的定义,所以我们还需要调用ApplicationContext接口的抽象实现类AbstractApplicationContext中的refresh()方法刷新容器,正如我们在前面看到的AnnotationConfigApplicationContext构造函数所执行的那样。可以说,refresh()方法是整个Spring容器中最为核心的一个方法,值得我们详细讨论。但因为这里关注的是依赖注入,所以我们只列出refresh()方法中与该主题相关的代码,如代码清单2-13所示。
代码清单2-13 AbstractApplicationContext中的refresh()方法代码
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 提取配置信息转化为BeanDefinition并注册到BeanFactory中 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); try { ... // 初始化所有的单例Bean finishBeanFactoryInitialization(beanFactory); ... } } }
可以看到,obtainFreshBeanFactory()方法完成BeanDefinition的注册并返回一个Bean-Factory。对于AnnotationConfigApplicationContext而言,这一步实际上就是将BeanDefinition注册到DefaultListableBeanFactory而已,我们在前面已经介绍了这一步骤。
而finishBeanFactoryInitialization()方法才是真正的完成Bean实例化的入口。在这个方法中,完成Bean的实例化代码实际上位于它的子类DefaultListableBeanFactory中,如代码清单2-14所示。
代码清单2-14 DefaultListableBeanFactory中的preInstantiateSingletons()方法代码
@Override public void preInstantiateSingletons() throws BeansException { List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // 触发所有非懒加载的单例Bean的初始化操作 for (String beanName : beanNames) { ... //获取Bean getBean(beanName); ... } }
接下来,我们就进入到getBean()方法了,这个方法可以从BeanFactory中获取一个Bean,而Bean的初始化过程也被封装在这个方法中。在getBean()方法中,我们一路跟踪代码会发现需要深入分析的实际上是如代码清单2-15所示的一个createBean()抽象方法。
代码清单2-15 BeanFactory中的createBean()方法代码
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException;
请注意,在Spring中,实现这个抽象方法的唯一BeanFactory是AbstractAutowireCap-ableBeanFactory。从命名上看,我们就可以联想到@Autowired注解。在AbstractAutowire-CapableBeanFactory中,真正完成Bean的创建是在doCreateBean()方法中。doCreateBean()方法比较长,为了显示得更简洁,我们对代码做了大量裁剪之后得到如代码清单2-16所示的结构。
代码清单2-16 AbstractAutowireCapableBeanFactory中的doCreateBean()方法代码结构
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { //1. 初始化Bean instanceWrapper = createBeanInstance(beanName, mbd, args); //2. 初始化Bean实例 populateBean(beanName, mbd, instanceWrapper); //3. 执行初始化Bean实例的回调 exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject; }
可以看到这里包含三个核心子方法,它们的名称和作用如图2-2所示。
图2-2 单例对象的初始化步骤示意图
在以上三个步骤中,createBeanInstance()方法用于根据配置生成具体的Bean,最终通过基于构造器的反射方法实现这一目标。请注意,执行完这一步之后,Bean已经被创建了,但还不完整,因为属性还没有被注入。
接下来的populateBean()方法就是用于实现属性的自动注入,包含byName、byType类型的自动装配,以及基于@Autowired、@Value注解的属性设值。执行完这一步之后,可以说Bean已经是完整的了。
而最后的initializeBean()方法则更多是一种扩展性的实现机制,用于在Bean初始化完成之后执行一些定制化操作。
至此,针对整个Bean的注入过程(即Bean的注册和实例化),我们围绕核心流程做了剖析和总结。在这个过程中,比较容易碰到的一个问题就是陷入代码的细节而忽略了主体步骤。因此,如果想要跳出源码阅读的困境,快速掌握框架的实现原理,我们就必须从核心流程来看待框架。
接下来,我们将对Spring依赖注入中典型的循环依赖问题进行系统分析。可以说,想要理解循环依赖问题以及对应的解决方案,掌握本节阐述的Bean的注册和实例化原理至关重要。