引题
spring框架最早是基于配置文件开发,后来引入注解的方式。回想下我最初使用spring框架的方式:
- 新建一个maven工程,引入spring相关jar包。
- 创建一个配置文件“spring.xml”。
- 创建测试类。
由此,spring框架创建了一个Man的实例。 可以想到,spring是根据“spring.xml”配置文件 中的< bean >标签创建了Man实例,下面通过源码看下具体的解析流程。
主流程解析
类的继承关系
ClassPathXmlApplicationContext 类
142 行:记录下配置文件名称 “spring.xml”。
143 行 :主流程
AbstractApplicationContext 类
@Override
// spring源码的大门,你准备好了么。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// xml 解析
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);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
523 行:主流程
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
方法总结:
1. 创建了BeanFactory对象。
2. xml解析
--默认标签解析:<bean>...
--自定义标签解析:<context:component-scan>
AbstractRefreshableApplicationContext 类
127 行:创建bean工厂
129 行:设置是否可以循环依赖
130 行:主流程,解析xml,加载BD(BeanDefinition) 点击进入 AbstractXmlApplicationContext 类
131 行:赋值给 AbstractRefreshableApplicationContext 类的属性。
AbstractXmlApplicationContext 类
83 行:委托模式
创建xml解析器。使用 XmlBeanDefinitionReader 解析xml配置文件。
94 行:主流程,加载BD(入参为XmlBeanDefinitionReader)
126 行:获取到需要加载的配置文件,最开始设置的 “spring.xml”
128 行:主流程
223 行:将配置文件转换为 Resource 对象(流的方式)
224 行:开始调用 XmlBeanDefinitionReader类 的加载BD方法
188 行:模板模式
,调到子类中的方法,这里调到 XmlBeanDefinitionReader 类
XmlBeanDefinitionReader 类
310 行:将 Resource 对象包装成 EncodedResource
333 行:获取到resource对象中的流对象
338 行:主流程
390 行:把inputSource 封装成Document文件对象,这是jdk的API
391 行:主流程。根据 Document 对象获取到里面的标签封装成 BD
509 行:委托模式
委托 BeanDefinitionDocumentReader这个类进行 Document 对象的解析
511 行:主流程
DefaultBeanDefinitionDocumentReader 类
121 行:入参为root节点
129 行:创建一个 BeanDefinitionParserDelegate 对象
148 行:解析之前调用,对root节点进行修饰。默认实现逻辑为空,可自定义
149 行:主流程。解析BD
148 行:解析之前调用,对root节点进行修饰。默认实现逻辑为空,可自定义。
该方法逻辑总结: 根据根节点获取到xml文件中配置的子节点集合进行遍历,判断节点类型(默认标签/自定义标签)并分别进行解析。
170 行:获取到根标签的子标签列表
175 行:判断是默认标签还是自定义标签
176 行:默认标签解析
179 行:自定义标签解析
到此,我们已经从配置文件中获取到了标签,接下来就是两种标签具体解析的逻辑。
总结
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
这行代码执行时,spring会根据入参找到配置文件,然后通过流的方式解析该文件并获取到文件里面的节点信息,再根据节点的类型分别进行解析(就是将标签转换为BeanDefinition)。
注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。