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

前言

这一章是就上一章的一个拓展说明,对通过文件输入流来分析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());
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值