Spring源码-Xml文件读取到BeanDefinition的封装

BeanFactory beanFactory = 
new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
User u = (User) beanFactory.getBean("u");

我们开始的第一步,一定是要读取XML文件,并将xml文件封装成JAVA对象。

那么Spring是如何读取配置文件的

ClassPathResource是Resource接口的子类实现类

Resource接口的作用:读取相关文件的内容 获得输入流

文件 ---xml .properties .txt ,网络中的资源,二进制流中,网络中,各种渠道获取内容,并转化为输入流,根据不同的需求来使用Resource不同的实现类

那么Java当中,以什么格式来体现xml文件呢?BeanDefinition

从这里开始执行

进入到方法内部,此处的reader为XmlBeanDefinitionReader,即我们的配置文件是由XmlBeanDefinitionReader进行读取解析的

	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		/*参数2,考虑到父子容器的出现,事实上这是非常少见的*/
		/*
		* 由XmlBeanDefinitionReader读入resource解析
		* */
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}

我们进入loadBeanDefinitions方法

	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<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专门用于解析的工具类(Sax),不是Spring的*/
				/*获得输入流之后,封装好解析类*/
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				/*(解析配置文件的工具,输入流)*/
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

通过上述的代码我们发现,在此方法中,获得了输入流,封装好了SAX的解析类,进入了doLoadBeanDefinitions方法

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			/*Document==>和Spring没关系,是XML解析所封装的一个对象
			* inputSource:Xml --> Document -->BeanDefinition
			* */
			Document doc = doLoadDocument(inputSource, resource);
			/*因为Document也不是Spring的对象,Document只是作为一个中间产物,为了Spring开发方便,Spring最终还是会将其转换为BeanDefinition*/
			int count = registerBeanDefinitions(doc, resource);
			/*count:封装对象的个数*/
			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);
		}
	}

我们发现上述的代码中,抛出了很多异常,真正有价值的是try中的代码。

通过解析,我们得到了一个Document类型的对象,是xml解析工具所封装的,为了Spring的使用方便,最终Spring会将其转化为BeanDefinition,此时这个只作为一个中间产物。

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		/*创建解析器类的新实例*/
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		/*已有的注册Bean对象的个数*/
		int countBefore = getRegistry().getBeanDefinitionCount();
		/*进行注册*/
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		/*现有的-以前有的=增加的*/
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

再次进入方法,我们分析发现,其中最核心的代码是中间部分,进行BeanDefinition的注册

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

将doc中的element取出,element就是<beans>标签,我们进入这个方法 

	protected void doRegisterBeanDefinitions(Element root) {
		/*root:对应的给定的根标记<beans>*/
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> 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.
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
			/*处理<profile>标签*/
			/*
				设置环境
			* <beans profile="dev"></beans>开发环境
			* <beans profile="production"></beans>生产环境
			* */
			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;
				}
			}
		}
		/*====================上面是设置环境================*/
		preProcessXml(root);
		/*=====================>核心<===========================*/
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

上述一部分代码在设置环境<profile>标签
            * <beans profile="dev"></beans>开发环境
            * <beans profile="production"></beans>生产环境
            * */

我们进入parseBeanDefinitions(root, this.delegate)方法

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			/*解析<beans>子节点*/
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						/*解析基本标签*
						<bean id="" class="" scope="" parent="" init-method=""
    						<property name  value
						</bean>
						<bean id="" class="" scope="" parent="" init-method=""
   	 						<construt-arg>
 						</bean>
						 */
						parseDefaultElement(ele, delegate);
					}
					else {
						/*解析自定义标签
						* 自定义标签:应用了新的命名空间的标签,
						* <context:propertyplace-holder
						<context:component-scan
						<tx:annotation-driven
						<mvc:annotation-drvent
						<aop:config
						* */
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

我们进入解析基本标签的方法

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		/*分门别类的选择*/
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			/*<import>标签
			* 引入其他配置文件
			* */
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			/*<Ailas>别名标签,(一个类的小名)*/
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			/*内嵌的Beans标签,即<beans></beans>内部又嵌套了一个<beans/>*/
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

注意最后一个else if,如果<beans>内部嵌套了<beans>标签,会再次进入doRegisterBeanDefinitions(ele);方法

我们进入<bean>标签的解析

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		/*
		BeanDefinitionParserDelegate 解析器  将<Bean>标签解析成BeanDefinitionHolder  Holder占位符
		* BeanDefinitionHolder:BeanDefinition的包装 :Bean的名字(Id) + 别名 + beanDefinition,用着方便
		* */
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			/*<bean>标签内部出现自定义标签*/
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				/*进行BeanDefinition的注册*/
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			/*发送注册完成事件,可以监听事件,做一些操作,但是目前是空的,可用于拓展*/
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

此处我们发现,成功的将输入流,转变为了BeanDefinition,但是Spring却将其封装为了BeanDefinitionHolder,BeanDefinitionHolder:BeanDefinition的包装 :Bean的名字(Id) + 别名 + beanDefinition,很显然,是为了后续处理更加方便。至此,我们完成了BeanDefinition的封装。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值