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
- 默认标签有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。
- 自定义标签解析
自定义标签是指带有前缀的标签,例如context:component-scan、aop:aspectj-autoproxy。这里只介绍component-scan标签的解析过程。
自定义标签必须在xml文件上方定义namespaceUri。根据当前解析标签的头信息找到对应的namespaceUri。在resolve方法中加载spring所有jar中的spring.handlers文件,并建立映射关系。这里用到了SPI设计思想的策略模式。
SPI: 1.加载配置文件,配置文件里面配置的都是类 2.配置文件可以定义在任何地方
根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类,这里是ContextNamespaceHandler。调用类的init方法,init方法是注册了各种自定义标签的解析类,最后返回ContextNamespaceHandler。
调用ContextNamespaceHandler.parse方法,找到component-scan对应的实现了BeanDefinitionParser接口的类——ComponentScanBeanDefinitionParser,用parse方法解析component-scan标签。
首先获取标签中的basePackage属性,然后创建扫描器,创建过程中添加了要扫描的注解类型是@Component,最后扫描并把类封装成BeanDefinition,注册BeanDefinition。
其中,doScan方法递归寻找basePackage下的.class文件,从AnnotationMetaData中获取类的基本信息,判断类上是否有要过滤出来的注解@Component。如果有,封装成BeanDefinition。
在ComponentScanBeanDefinitionParser解析方法的最后一步registerComponents中这行代码还完成了ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor的注册,这几个在后面会用到。