【spring源码-1】xml解析(上)

609 阅读4分钟

下一篇【spring源码-2】xml解析(中)默认标签解析

引题

spring框架最早是基于配置文件开发,后来引入注解的方式。回想下我最初使用spring框架的方式:

  1. 新建一个maven工程,引入spring相关jar包。
  2. 创建一个配置文件“spring.xml”。
  3. 创建测试类。

image.png

image.png

image.png

由此,spring框架创建了一个Man的实例。 可以想到,spring是根据“spring.xml”配置文件 中的< bean >标签创建了Man实例,下面通过源码看下具体的解析流程。

主流程解析

image.png

类的继承关系

ClassPathXmlApplicationContext 类

image.png

image.png 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();
                }
        }

image.png 523 行:主流程

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
方法总结:
1. 创建了BeanFactory对象。
2. xml解析
   --默认标签解析:<bean>...
   --自定义标签解析:<context:component-scan>
    

image.png

AbstractRefreshableApplicationContext 类

image.png image.png

127 行:创建bean工厂
129 行:设置是否可以循环依赖
130 行:主流程,解析xml,加载BD(BeanDefinition) 点击进入 AbstractXmlApplicationContext 类
131 行:赋值给 AbstractRefreshableApplicationContext 类的属性。

AbstractXmlApplicationContext 类

image.png 83 行:委托模式 创建xml解析器。使用 XmlBeanDefinitionReader 解析xml配置文件。
94 行:主流程,加载BD(入参为XmlBeanDefinitionReader)

image.png 126 行:获取到需要加载的配置文件,最开始设置的 “spring.xml”
128 行:主流程

image.png image.png 223 行:将配置文件转换为 Resource 对象(流的方式)
224 行:开始调用 XmlBeanDefinitionReader类 的加载BD方法

image.png 188 行:模板模式,调到子类中的方法,这里调到 XmlBeanDefinitionReader 类

XmlBeanDefinitionReader 类

image.png 310 行:将 Resource 对象包装成 EncodedResource
333 行:获取到resource对象中的流对象
338 行:主流程

image.png 390 行:把inputSource 封装成Document文件对象,这是jdk的API
391 行:主流程。根据 Document 对象获取到里面的标签封装成 BD

image.png 509 行:委托模式 委托 BeanDefinitionDocumentReader这个类进行 Document 对象的解析
511 行:主流程

DefaultBeanDefinitionDocumentReader 类

image.png image.png 121 行:入参为root节点
129 行:创建一个 BeanDefinitionParserDelegate 对象
148 行:解析之前调用,对root节点进行修饰。默认实现逻辑为空,可自定义
149 行:主流程。解析BD
148 行:解析之前调用,对root节点进行修饰。默认实现逻辑为空,可自定义。

image.png 该方法逻辑总结: 根据根节点获取到xml文件中配置的子节点集合进行遍历,判断节点类型(默认标签/自定义标签)并分别进行解析。

170 行:获取到根标签的子标签列表
175 行:判断是默认标签还是自定义标签
176 行:默认标签解析
179 行:自定义标签解析

到此,我们已经从配置文件中获取到了标签,接下来就是两种标签具体解析的逻辑。

总结

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

这行代码执行时,spring会根据入参找到配置文件,然后通过流的方式解析该文件并获取到文件里面的节点信息,再根据节点的类型分别进行解析(就是将标签转换为BeanDefinition)。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。

下一篇【spring源码-2】xml解析(中)默认标签解析