Spring 容器的启动和创建
·
第一步:容器启动阶段
加载配置文件过程(Web 环境)
- 在 Spring 的主配置文件
web.xml中配置ContextLoaderListener监听器,并通过<context-param>指定 Spring 配置文件位置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- 当 Servlet 容器(如 Tomcat)启动时:
-
- 为 Web 应用创建全局上下文环境
ServletContext; - 容器调用
web.xml中配置的ContextLoaderListener.contextInitialized()方法; - 该方法初始化
WebApplicationContext上下文(即 IoC 容器,默认实现为XmlWebApplicationContext); - 加载
context-param指定的配置文件信息到 IoC 容器中; - 最终,
WebApplicationContext实例以键值对形式保存在ServletContext中(键为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)。
- 为 Web 应用创建全局上下文环境
- 至此,IoC 容器的初始化正式开始。
通过 refresh() 方法启动整个容器(通用入口)
- 无论是 Web 环境还是独立应用,创建
ApplicationContext容器实例(如AnnotationConfigApplicationContext或ClassPathXmlApplicationContext)后,都会调用其refresh()方法来启动整个容器。 refresh()是容器初始化的统一入口,位于synchronized同步代码块中,确保多线程环境下容器只能被初始化一次。
第二步:BeanDefinition 的注册阶段
a. 资源定位(Resource Location)
- 容器通过
ResourceLoader将配置路径(如"classpath:beans.xml")解析为Resource对象。
Resource 是 Spring 对外部资源(类路径、文件系统、URL 等)的统一抽象(具体实现如 ClassPathResource、FileSystemResource),仅表示资源的位置,尚未执行任何 I/O 操作。
- 此阶段由
ResourceLoader完成,为后续读取操作提供资源句柄。
b. 资源载入与解析(Loading & Parsing)
- 使用对应的
BeanDefinitionReader(如XmlBeanDefinitionReader)读取Resource的输入流,解析其内容(如 XML 中的<bean>元素),生成结构化的BeanDefinition对象。 - 具体解析流程如下(源码级细节):
- 在
Reader读取器(如XMLBeanDefinitionReader.loadBeanDefinitions()方法)中,调用documentLoader(底层 XML 解析器)的方法,获得 DOMDocument对象; processBeanDefinition(Element, BeanDefinition)方法内部调用parseBeanDefinitionElement(),逐层解析具体的 XML 标签(如<bean>、<id>、<name>、<property>等),提取属性值,并将解析结果封装到BeanDefinitionHolder中(BeanDefinitionHolder是BeanDefinition的包装类,包含BeanDefinition、bean 名称、别名等信息,用于后续注册)。- 接着,在
Reader中调用processBeanDefinition()方法,传入Document的根元素(Element);
- 在
- 经过对
Document的逐层解析,XML 中定义的 Bean 配置被完整转换为 Spring 内部的BeanDefinition数据结构。 - 注意:此时仅完成元数据建模,依赖注入尚未发生,容器中存储的只是静态配置信息。
c. 注册(Registration)
- 将解析得到的
BeanDefinition以 bean 名称为 key,注册到BeanFactory内部的ConcurrentHashMap<String, BeanDefinition>中,供后续实例化使用。 - 注册的具体步骤如下:
-
- 在第 8 步的
processBeanDefinition()方法中,调用registerBeanDefinition(BeanDefinitionHolder)开始注册;
- 在第 8 步的
-
- 该方法最终执行
map.put(beanName, beanDefinition),将BeanDefinition存入注册表; registerBeanDefinition()方法内部使用synchronized同步代码块,保证并发环境下的数据一致性。
- 该方法最终执行
- 以上整个过程均由
BeanDefinitionReader(如XmlBeanDefinitionReader)在其loadBeanDefinitions()方法中完成。
Resource 定位与 refresh() 调用链(源码上下文)
整个 BeanDefinition 注册流程在 refresh() 方法中触发,具体调用链如下:
refresh()
└─ obtainFreshBeanFactory()
└─ refreshBeanFactory() (由 ClassPathXmlApplicationContext 重写实现)
└─ loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
├─ getResourceLoader().getResource("applicationContext.xml") → Resource(资源定位)
└─ new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(resource)(载入+解析+注册)
在构造 Spring IoC 容器时,首先需要明确 BeanDefinition 的来源(例如一个 XML 配置文件)。
Spring 通过 Resource 接口对各类外部资源进行统一抽象(如 ClassPathResource 表示类路径下的资源,FileSystemResource 表示文件系统中的资源)。
此时,容器仅完成资源定位,尚未读取或解析其内容。
真正的资源加载由 ResourceLoader 负责:它根据配置路径(如 "classpath:applicationContext.xml")解析出对应的 Resource 对象,为后续 I/O 操作提供基础。
容器初始化的核心流程(细化)
- 调用
refresh()方法:该方法位于synchronized同步块中,确保容器初始化过程线程安全; - 在 refresh()方法内部,创建
BeanFactory:在obtainFreshBeanFactory()内部,调用子类实现的refreshBeanFactory(),其中通过createBeanFactory()创建一个DefaultListableBeanFactory实例; - 加载
BeanDefinition:随后调用loadBeanDefinitions(BeanFactory),该方法由具体容器子类(如ClassPathXmlApplicationContext)实现; - 资源定位:
loadBeanDefinitions()首先通过ResourceLoader将配置路径转换为一个或多个Resource对象(即完成定位); - 资源读取与解析:根据配置类型选择对应的
BeanDefinitionReader(例如XmlBeanDefinitionReader用于 XML 配置,或通过ClassPathBeanDefinitionScanner扫描注解类),解析Resource中的内容。解析过程中,每个<bean>元素或每个被组件扫描发现的类,都会被转换为一个独立的BeanDefinition对象,其中包含该 bean 的类名、作用域、依赖关系、属性值等元数据。 - 最后,这些
BeanDefinition实例会被注册到BeanFactory的beanDefinitionMap中,以 bean 名称(bean name)为 key,BeanDefinition为 value 进行存储,供后续的 bean 实例化和依赖注入使用。
第三步:BeanFactory的初始化后续内容
public void refresh() {
// 1. 准备刷新(如设置启动时间、激活标志等)
prepareRefresh();
// 2. 【创建 BeanFactory】并【加载 BeanDefinition】→ 此时 BeanDefinition 被注册到 map 中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 配置 BeanFactory(设置类加载器、表达式解析器、忽略接口等)
prepareBeanFactory(beanFactory);
// 4. 【允许子类扩展 BeanFactory】(如注册 BeanPostProcessor 等)
postProcessBeanFactory(beanFactory);
// 5. 【调用 BeanFactoryPostProcessor】 → 可以修改已注册的 BeanDefinition!
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 【注册 BeanPostProcessor】(注意:不是执行,只是注册)
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源、事件广播器等(ApplicationContext 特有)
// 8. 【重点!】实例化所有非懒加载的单例 Bean
finishBeanFactoryInitialization(beanFactory); // ← 在这里才真正创建 Bean!
// 9. 完成刷新(发布事件等)
finishRefresh();
}更多推荐




所有评论(0)