一、spring xml解析过程

本文详细介绍了Spring框架中如何通过XmlBeanDefinitionReader进行Bean定义的解析过程,包括默认标签和自定义标签的处理方式。

注 :源码对应版本为 4.2.8.RELEASE

一、XmlBeanDefinitionReader

xml解析工作实际上是交给 XmlBeanDefinitionReader,从命名中也可以很清楚的理解它的用意

	/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 * @see #initBeanDefinitionReader
	 * @see #loadBeanDefinitions
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader 

	/**
	 * Register each bean definition within the given root {@code <beans/>} element.
	 */
	protected void doRegisterBeanDefinitions(Element root) {
		// 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);
    
        //是否是默认命名空间,因为一般我们的写法有两种
        //一种是 <bean name="" class="">
        //另一种是自定义扩展的标签 <mvc:annotation-driven/>
        //判断是否是默认命名空间的规则是:node.getNamespaceUri() 是否是 
        //spring固定的命名空间 http://www.springframework.org/schema/beans
		if (this.delegate.isDefaultNamespace(root)) {
            //读取profile属性,这个属性可以区分 生产,测试等,一般比较少用。
            //一般做法是使用maven打包指定profile
            //也可以实现自己的配置中心,这里不做详细的介绍
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					return;
				}
			}
		}

        //模版方法,默认实现为空,可以作为一个扩展点
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
        //模版方法,默认实现为空,可以作为一个扩展点
		postProcessXml(root);

		this.delegate = parent;
	}
	/**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 * @param root the DOM root element of the document
	 */
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //处理beans
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
                //只处理Element节点
				if (node instanceof Element) {
					Element ele = (Element) node;
                    //处理 import alias bean
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
                    //自定义标签处理
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
        //自定义标签处理
		else {
			delegate.parseCustomElement(root);
		}
	}

默认标签的解析还是挺清楚的:

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //解析import标签
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
        //解析alias标签
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
        //解析bean标签,也是最常用最复杂的标签
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
        //解析beans标签
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate 

处理自定义表情部分代码:

	public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //获取命名空间
		String namespaceUri = getNamespaceURI(ele);
        //根据命名空间获取相应的处理Handler,aop,jdbc,mvc都实现了相应的Handler,用户自定义的标签也需要实现该接口
        // 使用 NamespaceHandlerResolver 来获取 相应的 NamespaceHandler 
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
        //调用自定义的NamespaceHandler处理
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver 

	public NamespaceHandler resolve(String namespaceUri) {
        //获取handlerMapping
		Map<String, Object> handlerMappings = getHandlerMappings();
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
        //判断是否是对象类型
		else if (handlerOrClassName instanceof NamespaceHandler) {
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
        //类名称类型
			String className = (String) handlerOrClassName;
			try {
				Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                //类型检查,是否实现了NamespaceHandler 接口
				if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
					throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
							"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
				}
				NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                //初始化,init接口实际上是需要用户实现了
				namespaceHandler.init();
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
						namespaceUri + "] not found", ex);
			}
			catch (LinkageError err) {
				throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
						namespaceUri + "]: problem with handler class file or dependent class", err);
			}
		}
	}
	/**
	 * Load the specified NamespaceHandler mappings lazily.
	 */
	private Map<String, Object> getHandlerMappings() {
		if (this.handlerMappings == null) {
			synchronized (this) {
				if (this.handlerMappings == null) {
					try {
                        //从这句代码我们可以看到Spring读取了所有的 META-INF/spring.handlers 文件
                        //我们也可以在aop,mvc等jar里面找到该文件
                        //该文件里面定义了什么 namespaceUri 使用哪个 NamespaceHandler 来解析
                        //如http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
                        //用户自定义标签也只要遵循这个规则就可以了
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						if (logger.isDebugEnabled()) {
							logger.debug("Loaded NamespaceHandler mappings: " + mappings);
						}
						Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
						CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
						this.handlerMappings = handlerMappings;
					}
					catch (IOException ex) {
						throw new IllegalStateException(
								"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
					}
				}
			}
		}
		return this.handlerMappings;
	}

 

转载于:https://my.oschina.net/u/206123/blog/1547335

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值