Spring解析XML文件构建BeanDefinition对象


        一般通过3种方式搭建Spring框架:Spring xml、Spring注解、SpringBoot。Spring xml的方式很古老,现在基本上没人用,但是要知道Spring的底层原理,还得从xml讲起。

一、Spring解析XML文件

        解析XML文件从AbstractApplicationContext.obtainFreshBeanFactory中的refreshBeanFactory方法开始,refreshBeanFactory是典型的模板设计模式。找到AbstractApplicationContext的实现类AbstractRefreshableApplicationContext,然后看它的refreshBeanFactory方法。
在这里插入图片描述

Spring通过流的方式加载配置文件,封装成Resource对象。
在这里插入图片描述
loadBeanDefinitions用到了委托设计模式,将xml解析委托给了XmlBeanDefinitionReader。
在这里插入图片描述
        其中InputSource inputSource = new InputSource(inputStream)用到了jdk的sax解析。doLoadBeanDefinitions中把inputSource封装成Document文件对象。
在这里插入图片描述

        registerBeanDefinitions中又用到了委托设计模式,将document的解析委托给了BeanDefinitionDocumentReader。
在这里插入图片描述
        从documentReader.registerBeanDefinitions可以进入到DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions方法。parseBeanDefinitions方法是xml中标签的具体解析过程。
在这里插入图片描述

二、通过默认标签和自定义标签构建BeanDefinition

  1. 默认标签有import、bean、alias、beans,beans标签解析是循环解析标签里面的bean标签。
    在这里插入图片描述
    (1)这里只看bean标签的解析。delegate.parseBeanDefinitionElement(ele)是解析document,封装成BeanDefinition。在这个方法里面,创建了GenericBeanDefinition对象,解析bean标签的属性,并把解析出来的属性设置到BeanDefinition对象中。
    (2)最后通过BeanDefinitionRegistry.registerBeanDefinition注册BeanDefinition,注册是把BeanDefinition注册到beanDefinitionMap和beanDefinitionNames。
    (3)beanDefinitionMap是beanName对应beanDefinition的Map,beanDefinitionNames是保存beanName的List。
    在这里插入图片描述
  2. 自定义标签解析
            自定义标签是指带有前缀的标签,例如context:component-scan、aop:aspectj-autoproxy。这里只介绍component-scan标签的解析过程。
            自定义标签必须在xml文件上方定义namespaceUri。根据当前解析标签的头信息找到对应的namespaceUri。在resolve方法中加载spring所有jar中的spring.handlers文件,并建立映射关系。这里用到了SPI设计思想的策略模式。

SPI: 1.加载配置文件,配置文件里面配置的都是类 2.配置文件可以定义在任何地方

自定义标签解析
spring.handlers
        根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类,这里是ContextNamespaceHandler。调用类的init方法,init方法是注册了各种自定义标签的解析类,最后返回ContextNamespaceHandler。
resolve方法
ContextNamespaceHandler的init方法
        调用ContextNamespaceHandler.parse方法,找到component-scan对应的实现了BeanDefinitionParser接口的类——ComponentScanBeanDefinitionParser,用parse方法解析component-scan标签。
在这里插入图片描述
        首先获取标签中的basePackage属性,然后创建扫描器,创建过程中添加了要扫描的注解类型是@Component,最后扫描并把类封装成BeanDefinition,注册BeanDefinition。
在这里插入图片描述
        其中,doScan方法递归寻找basePackage下的.class文件,从AnnotationMetaData中获取类的基本信息,判断类上是否有要过滤出来的注解@Component。如果有,封装成BeanDefinition。
在这里插入图片描述
        在ComponentScanBeanDefinitionParser解析方法的最后一步registerComponents中这行代码还完成了ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor的注册,这几个在后面会用到。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/JustPlayCode/article/details/114315484