【spring源码】xml解析(上)
引题
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)。
作者:一支野菊花
链接:https://juejin.cn/post/7023608217984827422