第二节 Spring解析XML与装载BeanDefinition的过程

引子

我们都知道创建IOC容器的方式有以下常用几种:

FileSystemXmlApplicationContext fileSystemXmlApplicationContext=new FileSystemXmlApplicationContext("/application.xml");
FileSystemXmlApplicationContext fileSystemXmlApplicationContext1 = new FileSystemXmlApplicationContext("/application.xml");
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("/application.xml");
-- 工厂级别的
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));

但是万变不离其宗,我们通过源代码跟踪发现最终加载XML的实现类还是进了XmlBeanDefinitionReader类的

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   
		return loadBeanDefinitions(new EncodedResource(resource));
	}

方法中,这也是本节的重点。

解析XML与装载BeanDefinition

  1. 资源定位 resource
    Spring的配置文件读取是通过ClassPathResource进行封装的,这也正对应了上述方法中的参数,不过Resource是一个接口,在此不做过多阐述。

  2. 资源预处理

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
   
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
   
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
   
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
   
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
   
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
   
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				 // 核心步骤
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
		......	
	}

在这个阶段整理数据准备的逻辑,首先对传入的resource参数做封装,目的是考虑到 Resource可能存在编码要求的情况,其次,通过SAX读取XML文件的方式来准备InputSource 对象,最后将准备的数据通过参数传入真正的核心处理部分doLoadBeanDefinitions(inputSource, encodedResource. getResource())

  1. 验证XML
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
   
		try {
   
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		}
		......
	}
	
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   
		return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}		

其实只做了三件事,这三件事的每一件都 必不可少。

  • 获取对XML文件的验证模式。
  • 加载XML文件,并得到对应的Document
  • 根据返回的Document注册Bean信息。
    通过方法名字的关键字我们就能大体预支该方法的作用, Spring这一点做的非常好。这3个步骤支撑着整个Spring容器部分的实现,尤其是第3步对配置文件的解析,逻辑非 常的复杂,这也是我们重点关注的部分。在这里多嘴说一句在getValidationModeForResource()验证XML文件的时候提到了DTDXSD文件,具体两者的区别请参照[DTD与XSD]。(https://www.cnblogs.com/imsoft/p/6370077.html)
protected int getValidationModeForResource(Resource resource) {
   
		int validationModeToUse = getValidationMode();
		//如果手动指定了验证模式则使用指定的验证模式
		if (validationModeToUse != VALIDATION_AUTO) {
   
			return validationModeToUse;
		}
		//如果未指定则使用自动检测
		int detectedMode = detectValidationMode(resource);
		if (detectedMode != VALIDATION_AUTO) {
   
			return detectedMode;
		}
		return VALIDATION_XSD;
	}

在自动检测的代码中,Spring用来检 测验证模式的办法就是判断是否包含DOCTYPE,如果包含就是DTD,否则就是XSD。

  1. 获取Document
	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值