在第一章序言的图示中有提到,Spring中的配置文件都是通过各种的BeanDefinition来进行解析,并且支持不同类型的文件进行扩展。所以在创建完DefaultListableBeanFactory后,会通过BeanDefinition来解析传入的xml配置文件。
loadBeanDefinitions
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 创建一个XmlBeanDefinitionReader,并通过回调设置到beanFactory中
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		// Configure the bean definition reader with this context's
		// resource loading environment.
		// 给reader对象设置环境对象
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		//目的是读取本地文件库xsd.dtd等文件。
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		//  初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证
		initBeanDefinitionReader(beanDefinitionReader);
		// 开始完成beanDefinition的加载
		loadBeanDefinitions(beanDefinitionReader);
	}
ResourceEntityResolver
 在设置ResourceEntityResolver类时,会在父类构造器中设置这么几个变量,其中xsd和dtd文件主要是用来进行xml文件中标签的规范。
public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
		this.dtdResolver = new BeansDtdResolver();
		// 当完成这行代码的调用之后,大家神奇的发现一件事情,schemaResolver对象的schemaMappings属性被完成了赋值操作,但是你遍历完成所有代码后依然没有看到显式调用
		// 其实此时的原理是非常简单的,我们在进行debug的时候,因为在程序运行期间需要显示当前类的所有信息,所以idea会帮助我们调用toString方法,只不过此过程我们识别不到而已
		this.schemaResolver = new PluggableSchemaResolver(classLoader);
	}
public class BeansDtdResolver implements EntityResolver {
	private static final String DTD_EXTENSION = ".dtd";
	private static final String DTD_NAME = "spring-beans";
	//省略部分代码。。。
}
public class PluggableSchemaResolver implements EntityResolver {
	/**
	 * The location of the file that defines schema mappings.
	 * Can be present in multiple JAR files.
	 */
	public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
	//省略部分代码。。。
}	
loadBeanDefinitions
在Spring的框架中,会有很多地方都会调用loadBeanDefinitions方法,所以loadBeanDefinitions有很多的方法重载和重写,加载时,如果是configLocations的String类型文件名,会先将String转换成Resource,之后再调用Resource的loadBeanDefinitions进行文件的加载。所以整体是String[] -String-Resource[]- Resource的过程。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 以Resource的方式获得配置文件的资源位置
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// 以String的形式获得配置文件的位置
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}
String类型的loadBeanDefinitions实现
	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		//此处获取resourceLoader对象
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			//抛异常
		}
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				// 调用DefaultResourceLoader的getResource完成具体的Resource定位
				//getResources会根据location文件是否以classpath*:或者"war:等开头,来进行不同的实现
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				int count = loadBeanDefinitions(resources);
				if (actualResources != null) {
					Collections.addAll(actualResources, resources);
				}
				return count;
			}
			catch (IOException ex) {
				//抛异常
			}
		}
		else {
			// Can only load single resources by absolute URL.
			Resource resource = resourceLoader.getResource(location);
			int count = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			return count;
		}
	}
String转换为Resource后,还将继续Resource方法的loadBeanDefinitions方法的调用。
//将resource再封装成EncodeResource
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		// 通过属性来记录已经加载的资源
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (!currentResources.add(encodedResource)) {
			// 抛异常
		}
		
		// 从encodedResource中获取已经封装的Resource对象并再次从Resource中获取其中的inputStream
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			// 逻辑处理的核心步骤
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			// 抛异常
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
将Resource转换成Doc对象
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  {
		try {
			// 此处获取xml文件的document对象,这个解析过程是由documentLoader完成的,从String[] -String-Resource[]- Resource,最终开始将resource读取成一个document文档,根据文档的节点信息封装成一个个的BeanDefinition对象
			Document doc = doLoadDocument(inputSource, resource);
			int count = registerBeanDefinitions(doc, resource);
			return count;
		}
	}
创建BeanDefinitionDocumentReader来对doc对象的各个Elements进行解析
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 对xml的beanDefinition进行解析
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 完成具体的解析过程
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}



















