Spring内部机制的内容较多,所以打算多分几个阶段来写。
本章仅探索Spring容器启动做了哪些事;
前言:
都说Spring容器就像一台构造精妙的机器,此话一点不假,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式工作。
如果我们将Spring容器比喻为一辆汽车,可以将BeanFactory看成汽车的发动机,而ApplicationContext则是整辆汽车,它不但包括发动机,还包括离合器,变速器及底盘,车身,电器设备等其他组件,在ApplicationContext内,各个组件按部就班地完成汽车的各项功能。
正文:
Spring的AbstractApplicationContext是ApplicationContext的抽象实现类,该抽象类的refresh( )方法定义了Spring容器在加载配置文件后的各项处理过程,非常清晰。
我们来看一下这个方法内部定义了哪些执行逻辑。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // ① 初始化BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // ② 调用工厂后处理器 invokeBeanFactoryPostProcessors(beanFactory); // ③ 注册Bean后处理器 registerBeanPostProcessors(beanFactory); // ④ 初始化消息源 initMessageSource(); // ⑤ 初始化应用上下文事件广播器 initApplicationEventMulticaster(); // ⑥ 初始化其他特殊的Bean,由具体子类实现 onRefresh(); // ⑦ 注册事件监听器 registerListeners(); // ⑧ 初始化所有单实例的Bean,使用懒加载模式的Bean除外 finishBeanFactoryInitialization(beanFactory); // ⑨ 完成刷新并发布容器刷新事件 finishRefresh(); } catch (BeansException ex) { //略 } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
共九种主要的处理操作。下面再详细说说这些操作。
(1) 初始化BeanFactory: 根据配置文件实例化BeanFactory,在obtainFreshBeanFactory()方法中,首先调用refreshBeanFactory()方法刷新BeanFactory,然后调用getBeanFactory()方法获取BeanFactory,
这两个方法都是由具体子类实现的,在这一步里,Spring将配置文件的信息装入容器的Bean定义注册表(BeanDefinitionRegistry)中,但此时Bean还未初始化。
附上obtainFreshBeanFactory()方法的源码如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
(2) 调用工厂后处理器: 根据反射机制从BeanDefinitionRegistry中找出所有实现了BeanFactoryPostProcessor接口的Bean,并调用其postProcessBeanFactory()接口方法。也附上部分源码吧。
if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>(); List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryPostProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryPostProcessor.postProcessBeanDefinitionRegistry(registry); registryPostProcessors.add(registryPostProcessor); } else { regularPostProcessors.add(postProcessor); } }
(3) 注册Bean后处理器: 根据反射机制从BeanDefinitionRegistry中找出所有实现了BeanPostProcessor接口的Bean,并将它们注册到容器Bean后处理器的注册表中。
(4) 初始化消息源: 初始化容器的国际化消息资源。想必这个比较好理解。
(5) 初始化应用上下文事件广播器。
(6) 初始化其他特殊的Bean: 这是一个钩子方法,子类可以借助这个方法执行一些特殊的操作,如AbstractRefreshableWebApplicationContext就使用该方法执行初始化ThemeSource的操作。
(7) 注册事件监听器。
(8) 初始化所有单实例的Bean,使用懒加载模式的Bean除外:初始化Bean后,将它们放入Spring容器的缓存池中。(加一句:如果这个有懒加载标志的单实例Bean被一个非懒加载的单实例Bean引用时,那么懒加载失效)
(9) 发布上下文刷新事件: 创建上下文刷新事件,事件广播器负责将这些事件广播到每个注册的事件监听器中。(关于事件的内容在下面的章节会有详解)
下一章节讲Spring容器从加载配置文件到创建出一个完整Bean的作业流程及参与的角色。