栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

1. Spring 源码:Spring 解析XML 配置文件,获得 Bena 的定义信息

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

1. Spring 源码:Spring 解析XML 配置文件,获得 Bena 的定义信息

通过 Debug 运行 XmlBeanDefinitionReaderTests 类的 withFreshInputStream() 的方法,调试 Spring 解析 XML 配置文件,获得 Bean 的定义。

大体流程可根据序号查看,xml 配置文件随便看一眼,不用过多在意。






	
		
			I have no properties and I'm happy without them.
		
	

	
	
		aliased
	

	

	

	
		aliased
	

	

	
		aliased
	

	
		
	

	

	

	

	
		Rod
		31
		
		
	

	
		Roderick
		
	

	
		Kerry
		34
		
		
	

	
		Kathy
		28
		
	

	
		typeMismatch
		34x
		
	

	
	

	
		true
	

	
		true
	

	
	
	

	
		false
	

	
	
		
		
		
	

	
		
		
		
	

	
	
		
		
	

	
		listenerVeto
		66
	

	

	
	  this is a ]]>
	


	@Test
	public void withFreshInputStream() {
        // TODO 1.创建 SimpleBeanDefinitionRegistry 对象,提供注册BeanDefinition功能
		SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
        // TODO 2.获取配置文件
		Resource resource = new ClassPathResource("test.xml", getClass());
        // TODO 3.创建 XmlBeanDefinitionReader 对象,提供读取 XMl 文件中的 Bean 的定义信息;
		new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
        // TODO 30.验证 BeanDefinitions 信息;
		testBeanDefinitions(registry);
		System.out.println("success");
	}

	private void testBeanDefinitions(BeanDefinitionRegistry registry) {
		assertThat(registry.getBeanDefinitionCount()).isEqualTo(24);
		assertThat(registry.getBeanDefinitionNames().length).isEqualTo(24);
		assertThat(Arrays.asList(registry.getBeanDefinitionNames()).contains("rod")).isTrue();
		assertThat(Arrays.asList(registry.getBeanDefinitionNames()).contains("aliased")).isTrue();
		assertThat(registry.containsBeanDefinition("rod")).isTrue();
		assertThat(registry.containsBeanDefinition("aliased")).isTrue();
		assertThat(registry.getBeanDefinition("rod").getBeanClassName()).isEqualTo(TestBean.class.getName());
		assertThat(registry.getBeanDefinition("aliased").getBeanClassName()).isEqualTo(TestBean.class.getName());
		assertThat(registry.isAlias("youralias")).isTrue();
		String[] aliases = registry.getAliases("aliased");
		assertThat(aliases.length).isEqualTo(2);
		assertThat(ObjectUtils.containsElement(aliases, "myalias")).isTrue();
		assertThat(ObjectUtils.containsElement(aliases, "youralias")).isTrue();
	}
	
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		// TODO 4.将读取的XML资源进行特殊的编码处理
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		Set currentResources = this.resourcesCurrentlyBeingLoaded.get();

		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		// TODO 5. 将资源文件转为InputStream的I/O流
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) { // TODO 只有是Closeable的子类才能这样书写,有点是系统会自动帮助我们关闭
			// TODO 从InputStream中得到XML的解析源
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			// TODO 6.具体读取过程
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
            // TODO 29. 
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
	
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			// TODO 7. 加载Bean配置信息,并转换为文档对象
			Document doc = doLoadDocument(inputSource, resource);
			// TODO 8. 对Bean定义进行解析
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}
	
	
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// TODO 9.得到BeanDefinitionDoucumentReader来对XML格式的BeanDefinition进行解析
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// TODO 10.获得容器中注册的Bean数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		// TODO 11. 解析过程的入口,这里使用了委派模式,BeanDefinitionDocumentReader只是一个接口
		// TODO 具体的解析过程由实现类DefaultBeanDefinitionDocumentReader完成
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// TODO 28. 统计解析的Bean数量
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
	
	
	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		// TODO 获得XML描述符
		this.readerContext = readerContext;
		// TODO 12. doc.getDocumentElement() 获的Document根元素
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}
	@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
	protected void doRegisterBeanDefinitions(Element root) {
		// Any nested  elements will cause recursion in this method. In
		// order to propagate and preserve  default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.
		// TODO 具体的解析过程由BeanDefinitionParserDelegate实现
		// TODO BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各元素
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		// TODO 校验是否引入 beans schemaLocation
		if (this.delegate.isDefaultNamespace(root)) {

			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		// TODO 在解析Bean定义之前,进行自定义解析,增强解析过程的可扩展性
		preProcessXml(root);
		// TODO 12.从文档的根元素开始进行Bean定义的文档对象的解析
		parseBeanDefinitions(root, this.delegate);
		// TODO 27.在解析Bean定义之后,进行自定义解析,增强解析过程的可扩展性
		postProcessXml(root);

		this.delegate = parent;
	}
	
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// TODO 13. Bean定义的文档对象使用了Spring默认的XML命名空间
		if (delegate.isDefaultNamespace(root)) {
			// TODO 14. 获取Bean定义的文档对象根元素的所有子节点
			NodeList nl = root.getChildNodes();
            // TODO 此处是循环,忽略需要,需要是大体执行流程不是唯一
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				// TODO 15. 获得的文档节点是XML元素节点
				if (node instanceof Element ele) {
					// TODO 16. Bean定义的文档的元素节点使用的是Spring默认的XML命名空间
					if (delegate.isDefaultNamespace(ele)) {
						// TODO 17. 使用Spring的Bean规则解析元素节点
						parseDefaultElement(ele, delegate);
					}
					else {
						// TODO 如果没有使用Spring默认的XMl命名空间,则使用用户自定义的规则解析元素节点
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			// TODO 如果没有使用Spring默认的XMl命名空间,则使用用户自定义的规则解析元素节点
			delegate.parseCustomElement(root);
		}
	}
	
	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		// TODO 18.如果节点是导入元素,进行导入元素解析
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// TODO 19.如果节点是别名元素,进行别名解析
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// TODO 20.如果节点是元素,则按照Spring的Bean规则解析元素
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		// TODO 如果节点是元素,则按照Spring的Bean规则解析元素
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}
	
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		// TODO 21. BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
		// TODO 对文档对象中元素的解析由BeanDefinitionParserDelegate实现
		// TODO BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 22.Register the final decorated instance.
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			// TODO 26.在完成向Spring Ioc容器注册解析得到的Bean定义之后,发送注册事件
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}
	
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {
		// Register bean definition under primary name.
		// TODO 获取解析的beanDefinition的名称
		String beanName = definitionHolder.getBeanName();
		// TODO 23.向Spring Ioc容器注册BeanDefinition
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		// TODO 25.如果解析的BeanDefinition有别名,向Spring Ioc容器注册别名
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
	
    @Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "'beanName' must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        // TODO 24.存储 BeanDefinition 
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/962342.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号