Spring源码导读之Xml文件解析

Spring源码导读

 

目录

xml基础知识

BeanDefinition

ClassPathXmlApplicationContext

XmlBeanDefinitionReader

DefaultDocumentLoader

DefaultBeanDefinitionDocumentReader ->BeanDefinitionParserDelegate

NameSpaceHandler


 

BeanDefinition

Spring会先将各种途径加载的资源中定义的Bean属性统一转换为BeanDefinition。下面是我列出它的主要方法。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
	/**
	 * Bean的父类
	 */
	void setParentName(@Nullable String parentName);
	/**
	 * Bean的类全路径名称
	 */
	void setBeanClassName(@Nullable String beanClassName);
	/**
	 * Bean的作用域
	 */
	void setScope(@Nullable String scope);
	/**
	 * 是否懒加载
	 */
	void setLazyInit(boolean lazyInit);
	/**
	 * 如果是工厂模式加载的Bean,设置它的工厂
	 */
	void setFactoryBeanName(@Nullable String factoryBeanName);
	/**
	 * 工厂方法模式加载的Bean 设置它的工厂方法
	 */
	void setFactoryMethodName(@Nullable String factoryMethodName);
	/**
	 * 构造器的参数
	 */
	ConstructorArgumentValues getConstructorArgumentValues();
	/**
	 * Bean的属性
	 */
	MutablePropertyValues getPropertyValues();
	/**
	 * 是否是单例
	 */
	boolean isSingleton();
	/**
	 * 是否是多例
	 */
	boolean isPrototype();
	/**
	 * 是否抽象类
	 */
	boolean isAbstract();
}

 

ClassPathXmlApplicationContext

其构造方法,可以看到 会调用一次refresh方法。

	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			// Spring容器的刷新,Spring的主要代码就是从这里开始的
			refresh();
		}
	}

org.springframework.context.support.AbstractApplicationContext#refresh  查看类图

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();
			// 主要看这里,获取一个新鲜的Bean工厂,这也是资源加载和XML解析成BeanDefinition的入口
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// 。。。后面先不看
		}
	}

org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory 查看类图

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		// 刷新Bean工厂,这里面会调用其子类 AbstractRefreshableApplicationContext#refreshBeanFactory 
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory 查看类图

	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			// 创建一个DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			// 这里交给子类自定义
			customizeBeanFactory(beanFactory);
			// 主要看这里 这里开始加载Bean的定义,将刚刚创建的beanFactory传下去,用于后面的注册
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)  查看类图

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// XmlBeanDefinitionReader 解析完xml之后需要注册Bean定义,将beanFactory作为注册表床给它
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// 设置环境,后面解析时会用到,根据不同环境(如开发或测试环境)选择是否加载该xml,
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		// AbstractApplicationContext 在类图中我们能看到他是继承了ResourceLoader的, 它是由加载资源的能力的, 因此将this传入
		beanDefinitionReader.setResourceLoader(this);
		// 帮助reader在不联网的情况下能找到我们的本地schama文件
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
		// 允许子类去初始化,在这里默认逻辑只会设置,是否对xml的名称空间进行校验
		initBeanDefinitionReader(beanDefinitionReader);
		// 配置完XmlBeanDefinitionReader 后开始其加载
		loadBeanDefinitions(beanDefinitionReader);
	}

 

ClassPathXmlApplicationContext 的Resource[] 的获取是在后面实现的,因此在这里会根据我们配置的 文件路径进行加载

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }

   // 我们当前案例在此事还未得到Resource,因此走这条链路,根据location进行load
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      // 委托reader进行加载
      reader.loadBeanDefinitions(configLocations);
   }
}

 

XmlBeanDefinitionReader

 

容易调用reader去加载文件,一开始是先调用其父类AbstractBeanDefinitionReader的loadBeanDefinitions(String... locations)  --> loadBeanDefinitions(String location)

 

location可以配置多个,为每个加载每个location,并计数。

	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int counter = 0;
		for (String location : locations) {
			counter += loadBeanDefinitions(location);
		}
		return counter;
	}

加载单个location,先获得其Resource[]或 Resource,因为我们的location可能配置的是“classpath*/aa/bb/**.xml” 这种pattern形式,因此每个location会得到多个Resource,并且reader的resourceLoader 其实就是ClassPathXmlApplicationContext,而ClassPathXmlApplicationContext是实现ResourcePatternResolver的,因此会使用ResourcePatternResolver加载多个资源。

查看类图

	public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(location, null);
	}


public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		// 拿到ResourceLoader 其实就是容器
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		// 判断容器是否是实现了ResourcePatternResolver, 容器是肯定是实现它,需要通过模式匹配加载多个资源
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				// 使用ResourcePatternResolver进行模式匹配形式的加载资源
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 调用子类(xml,Properties 等不同文件形式的子类)进行具体的load
				int loadCount = loadBeanDefinitions(resources);
				if (actualResources != null) {
					for (Resource resource : resources) {
						actualResources.add(resource);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// 如果不是则直接用resourceLoader进行加载资源
			Resource resource = resourceLoader.getResource(location);
			// 调用子类(xml,Properties 等不同文件形式的子类)进行具体的load
			int loadCount = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}

 

从上面看出AbstractBeanDefinitionReader是一个骨架,它做的是 计数 + 加载资源。BeanDefinition的加载是通过传入Resource给方法BeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)交给子类去实现的。

下面我们介绍xml如何XmlBeanDefinitionReader如何解析xml文件。

下补一下xml的基本知识

 

上面都是调用AbstractBeanDefinitionReader的,接下来才是其具体文件形式的reader介绍:

 

XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)。

它需要传入一个EncodedResource ,其实就是Resource加了编码。

	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("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 {
			// 根据Resource获得其文件流
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				// 封装成InputSource
				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();
			}
		}
	}

下面代码可以看到,doLoadBeanDefinitions分为两步1、加载Document ,2、针对得到的Document 对解析出beanDefitnion并将其注册

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			// 加载Document
			Document doc = doLoadDocument(inputSource, resource);
			// 注册
			return registerBeanDefinitions(doc, resource);
		}
		//后面不用看,不写了 。。。。。
	}

 

先看加载Document,  XmlBeanDefinitionReader 将Document 委托给documentLoader(其实现其实是DefaultDocumentLoader

)进行加载。

loadDocument接受几个参数:

  •      * @param inputSource 我们的资源,里面封装了InputStream的文件流。
  •      * @param entityResolver XSD的解析者
  •      * @param errorHandler 错误处理者 
  •      * @param validationMode 校验模式 
  •      * @param namespaceAware 是否感知xml的名称空间

后面四个参数在有简单案例进行解释

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
         getValidationModeForResource(resource), isNamespaceAware());
}

 

DefaultDocumentLoader

DefaultDocumentLoader#loadDocument

xml是使用dom工具对xml进行解析的。

	/**
	 * Load a {@link Document document} from the supplied {@link InputSource source}.
	 * @param inputSource the source of the document that is to be loaded
	 * @param entityResolver XSD的解析者
	 * @param errorHandler 错误处理者
	 * @param validationMode 校验模式
	 * @param namespaceAware 是否感知xml的名称空间
	 */
	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

		// 主要是factory.setValidating(true) 和 factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isDebugEnabled()) {
			logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
		// docBuilder.setEntityResolver(entityResolver)和docBuilder.setErrorHandler(errorHandler)
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		// 解析资源,并将Document返回
		return builder.parse(inputSource);
	}

 

DefaultBeanDefinitionDocumentReader

好拿到Document 后,针对Document进行BeanDefinition的注册,注册这个工作XmlBeanDefinitionReader又将其委托给了BeanDefinitionDocumentReader 。

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 交给 BeanDefinitionDocumentReader  对 Document进行阅读
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

 

DefaultBeanDefinitionDocumentReader#registerBeanDefinitions:传入Document和reader上下文,其实就是XmlReaderContext,里面封装了一些上文需要用到的,比如注册表(其实就是beanFactory)。对Document 的解析是从其root开始的:

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   Element root = doc.getDocumentElement();
   // 拿到root进行解析
   doRegisterBeanDefinitions(root);
}

 

拿到root后,

1、DefaultBeanDefinitionDocumentReader会判断这个root是不是beans的默认名称空间(空或者等于”http://www.springframework.org/schema/beans")如果是默认名称空间,会对名称空间的一个属性“profile”,进行判断,判断其是否为当前环境(dev,test,uat等),如果该文件不属于当前环境则停止解析。因此spring支持多套环境的不同配置

2、开始对root进行解析。

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);

		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);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isInfoEnabled()) {
						logger.info("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;
	}

 

 

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions。这里再次判断root是否是默认名称空间的,如果是则解析,如果不是则调用自定义解析。并且解析的时候对每个node都会判断是否属于名称空间,如果是则解析,如果不是则调用自定义解析

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 如果root是默认名称空间的
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			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)) {
						// 如果是默认名称空间的
						parseDefaultElement(ele, delegate);
					}
					else {
						// 自定义解析
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//如果是自定义解析
			delegate.parseCustomElement(root);
		}
	}

 

先看默认解析,这里判断Element 的名字是不是 import,alias,bean或者beans。调用其对应的解析方法

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

 

我们看它对bean是如何解析的。

  • 先使用delegate解析得到一个BeanDefinitionHolder,这个BeanDefinitionHolder其实就是封装了(beanName + alias + beanDefinition)。
  • 然后再对BeanDefinition进行一次修饰,这里用户可以自定义对得到的
  • 调用工具对BeanDefinition进行注册
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

		// 获得BeanDefinitionHolder(beanName + alias + beanDefinition)
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 这里会对bean的属性进行一次修饰,有些属性属于自定义的,这里会拿到它名称空间的HandlerResolver对其解析:this.readerContext.getNamespaceHandlerResolver()
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 最后对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));
		}
	}

 

BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element) 

从代码中看到,id,name的关系,如果我们定义了id,那么将id作为beanName,如果没有定义name,那么将name属性按照",; "进行分割,取第一个作为beanName,其他作为aliases。如果都为空会按照类名为它生成一个beanName

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		//检查beanName和别名的唯一性
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		
		// 对bean的其他属性如class, 父类 等进行赋值
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						// 如果没有beanName,readerContext会按照类名和计数的方式为它生成一个beanName
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
		
			// 创建一个抽象的AbstractBeanDefinition, 为其设置它的Class(如果上下文有classLoader的话)或者className,设置它的parent
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			// 解析其属性, 是否是单例,是否懒加载等等
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			parseMetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			// 设置其构造函数参数
			parseConstructorArgElements(ele, bd);
			
			// 设置其bean的成本变量,bd.getPropertyValues().addPropertyValue(pv); RuntimeBeanReference 或者TypedStringValue
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

 

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
   NodeList nl = beanEle.getChildNodes();
   for (int i = 0; i < nl.getLength(); i++) {
      Node node = nl.item(i);
	  // 遍历直到解析到property
      if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
         parsePropertyElement((Element) node, bd);
      }
   }
}

 

	public void parsePropertyElement(Element ele, BeanDefinition bd) {
		String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
		if (!StringUtils.hasLength(propertyName)) {
			error("Tag 'property' must have a 'name' attribute", ele);
			return;
		}
		this.parseState.push(new PropertyEntry(propertyName));
		try {
			if (bd.getPropertyValues().contains(propertyName)) {
				error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
				return;
			}
			Object val = parsePropertyValue(ele, bd, propertyName);
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}

 

public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
		String elementName = (propertyName != null ?
				"<property> element for property '" + propertyName + "'" :
				"<constructor-arg> element");

		// Should only have one child element: ref, value, list, etc.
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}

		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		if (hasRefAttribute) {
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		else if (hasValueAttribute) {
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		else if (subElement != null) {
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}

NameSpaceHandler

用于自定义解析,自定义解析,先看一个案例

讲解:

前面代码讲到 DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法开始从root节点对Element进行解析

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 如果root是默认名称空间的
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			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)) {
						// 如果是默认名称空间的
						parseDefaultElement(ele, delegate);
					}
					else {
						// 自定义解析
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//如果是自定义解析
			delegate.parseCustomElement(root);
		}
	}

BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element)的代码

	public BeanDefinition parseCustomElement(Element ele) {
		return parseCustomElement(ele, null);
	}

	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		// 获取自定义名称空间的URL
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		/**
		* 这个readerContext 是前面registerBeanDefinitions中传入的: documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		* 这个readerContext 中有一个DefaultNamespaceHandlerResolver 它会根据namespaceUri获得一个我们自定义的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解析 Element
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

看一下这个获取nameSpace的方法

	public NamespaceHandler resolve(String namespaceUri) {
		// 获取一个 key = namespace, value = NamespaceHandler的map
		Map<String, Object> handlerMappings = getHandlerMappings();
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
		// 如果它实现了NamespaceHandler直接返回如果不是则加载它的Class并实例化返回
		else if (handlerOrClassName instanceof NamespaceHandler) {
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
			String className = (String) handlerOrClassName;
			try {
				Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
				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);
				namespaceHandler.init();
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
						"] for namespace [" + namespaceUri + "]", ex);
			}
			catch (LinkageError err) {
				throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
						className + "] for namespace [" + namespaceUri + "]", err);
			}
		}
	}

resolve方法一进来getHandlerMappings 这个handlerMappings放置了所有名称空间对应的handler。getHandlerMappings()是一个懒加载模式。它是阅读handlerMappingsLocation = "META-INF/spring.handlers"这个文件进行加载的。

private Map<String, Object> getHandlerMappings() {
		Map<String, Object> handlerMappings = this.handlerMappings;
		if (handlerMappings == null) {
			synchronized (this) {
				handlerMappings = this.handlerMappings;
				if (handlerMappings == null) {
					if (logger.isDebugEnabled()) {
						logger.debug("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
					}
					try {
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						if (logger.isDebugEnabled()) {
							logger.debug("Loaded NamespaceHandler mappings: " + mappings);
						}
						handlerMappings = new ConcurrentHashMap<>(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 handlerMappings;
	}

 

NamespaceHandler 有三个方法,可以自定义解析,解析完之后可以自定义修饰一波。

public interface NamespaceHandler {
	void init();

	@Nullable
	BeanDefinition parse(Element element, ParserContext parserContext);

	@Nullable
	BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);

}

他们分配在

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

被调用

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

		// 获得BeanDefinitionHolder(beanName + alias + beanDefinition)
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 这里会对bean的属性进行一次修饰,有些属性属于自定义的,这里会拿到它名称空间的HandlerResolver对其解析:this.readerContext.getNamespaceHandlerResolver()
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 最后对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));
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值