举个例子,我们xml里一般不是有如下代码吗:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/context/spring-context.xsd">上面的代码,应该就是去获取和解析上面这里的xsd,方便进行语法校验的。毕竟,这个xml我们也不能随便乱写吧,比如,根元素就是,有且 只能有一个,下面才能有0到多个之类的元素。你要是写了多个根元素,肯定不合规范啊。
接下来,我们还是赶紧切入正题吧,看看XmlBeanDefinitionReader是怎么解析xml的。
XmlBeanDefinitionReader 解析xml protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); //这个方法还在:AbstractXmlApplicationContext,获取资源位置,传给 XmlBeanDefinitionReader if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }经过几个简单跳转,进入下面的方法:
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>) public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader instanceof ResourcePatternResolver) { try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); // 从资源数组里load bean definition int loadCount = loadBeanDefinitions(resources); return loadCount; } } } XmlBeanDefinitionReader类图这里插一句,看看其类图:
总的来说,类似于模板设计模式,一些通用的逻辑和流程,放在AbstractBeanDefinitionReader,具体的解析啊,都是放在子类实现。
我们这里也可以看到,其实现了一个接口,BeanDefinitionReader:
package org.springframework.beans.factory.support; public interface BeanDefinitionReader { // 为什么需要这个,因为读取到bean definition后,需要存到这个里面去;如果不提供这个,我读了往哪放 BeanDefinitionRegistry getRegistry(); //资源加载器,加载xml之类,当然,作为一个接口,资源是可以来自于任何地方 ResourceLoader getResourceLoader(); //获取classloader ClassLoader getBeanClassLoader(); // beanName生成器 BeanNameGenerator getBeanNameGenerator(); // 从资源load bean definition int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException; int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException; int loadBeanDefinitions(String location) throws BeanDefinitionStoreException; int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException; }我们切回前面,AbstractBeanDefinitionReader实现了大部分方法,除了下面这个:
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;因为,它毕竟只是个抽象类,不负责干活啊;而且,为了能够从不同的resource读取,这个也理应交给子类。
比如,我们这里的XmlBeanDefinitionReader就是负责从xml文件读取;我之前的文章里,也演示了如何从json读取,也是自定义了一个AbstractBeanDefinitionReader的子类。
读取xml文件为InputSource接着上面的方法往下走,马上就进入到了:
位置:org.springframework.beans.factory.xml.XmlBeanDefinitionReader,插入的参数,就是我们的xml public int loadBeanDefinitions(EncodedResource encodedResource) { ... try { // 读取xml文件为文件流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //读取为xml资源 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } // 解析bean definition去 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } } }这里,提一句InputSource,这个类的全路径为:org.xml.sax.InputSource,是jdk里的类。
包名里包括了xml,知道大概是xml相关的类了,包名也包含了sax,大概知道是基于sax事件解析模型。