Spring源码解析之配置信息解析

导读:本篇文章讲解 Spring源码解析之配置信息解析,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

前言

这一章是就上一章的一个拓展说明,对通过文件输入流来分析spring是如何对xml配置文件来进行解析的!

核心代码

		//获取输入流,这是7的代码特性,InputStream实现了Closeable接口,不必手动关闭流
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			//sax解析
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				//将显式设置的编码设置进去
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			//do开头的方法是spring内部调用的方法不希望被外界所使用
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				//不调用会产生内存泄漏
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}

首先看doLoadBeanDefinitions的方法

//doc获取到的文档对象
Document doc = doLoadDocument(inputSource, resource);
//完成解析
int count = registerBeanDefinitions(doc, resource);

下面是一堆异常catch我就不贴了,这里面这个方法返回的是读取bean的个数,在这里吗又有两个核心的方法doLoadDocument和registerBeanDefinitions

doLoadDocument流程解析

	/**
	 * 使用配置的DocumentLoader实际加载指定的文档。
	 * Actually load the specified document using the configured DocumentLoader.
	 * @param inputSource the SAX InputSource to read from
	 * @param resource the resource descriptor for the XML file
	 * @return the DOM Document
	 * @throws Exception when thrown from the DocumentLoader
	 * @see #setDocumentLoader
	 * @see DocumentLoader#loadDocument
	 */
	protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
		return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}

isNamespaceAware:返回XML解析器是否应了解XML名称空间。
documentLoader是什么?

private DocumentLoader documentLoader = new DefaultDocumentLoader();

loadDocument方法:

	@Override
	//完成对doc文档的读取
	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isTraceEnabled()) {
			logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		return builder.parse(inputSource);
	}

然后把当前对象的document对象给返回回去!

registerBeanDefinitions解析

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//获取到解析之前的定义在bean工厂下面的bean的数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//现在解析完的减去已经解析过得,防止配置文件中有相互引用的问题,会导致再次引用!
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

首先我们看createBeanDefinitionDocumentReader:
在这里插入图片描述
在进入
在这里插入图片描述
主要是使用了Java反射的机制

	/**
	 * 使用给定构造函数实例化类的便捷方法。
	 * 请注意,如果给定了不可访问的(即非公共的)构造函数,则此方法尝试将构造函数设置为可访问,
	 * 并支持带有可选参数和默认值的Kotlin类。
	 * 
	 * Convenience method to instantiate a class using the given constructor.
	 * <p>Note that this method tries to set the constructor accessible if given a
	 * non-accessible (that is, non-public) constructor, and supports Kotlin classes
	 * with optional parameters and default values.
	 * @param ctor the constructor to instantiate
	 * @param args the constructor arguments to apply (use {@code null} for an unspecified
	 * parameter, Kotlin optional parameters and Java primitive types are supported)
	 * @return the new instance
	 * @throws BeanInstantiationException if the bean cannot be instantiated
	 * @see Constructor#newInstance
	 */
	public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			//爆破访问
			ReflectionUtils.makeAccessible(ctor);
			//Kotlin判断
			if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
				return KotlinDelegate.instantiateClass(ctor, args);
			}
			//java类走下面判断
			else {
				Class<?>[] parameterTypes = ctor.getParameterTypes();
				Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
				Object[] argsWithDefaultValues = new Object[args.length];
				for (int i = 0 ; i < args.length; i++) {
					if (args[i] == null) {
						Class<?> parameterType = parameterTypes[i];
						argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
					}
					else {
						argsWithDefaultValues[i] = args[i];
					}
				}
				//获取对象实例
				return ctor.newInstance(argsWithDefaultValues);
			}
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
		}
	}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16383.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!