java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > applicationContext与NamespaceHandler解析

spring的applicationContext.xml文件与NamespaceHandler解析

作者:服务端开发

这篇文章主要介绍了spring的applicationContext.xml文件与NamespaceHandler解析,Spring容器启动,在创建BeanFactory时,需要加载和解析当前ApplicationContext对应的配置文件applicationContext.xml,从而获取bean相关的配置信息,需要的朋友可以参考下

applicationContext.xml文件解析

NamespaceHandler

Spring内部的使用和源码实现

http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler

对应的NamespaceHandler的实现类为:

package org.springframework.web.servlet.config;
/**
 * {@link NamespaceHandler} for Spring MVC configuration namespace.
 *
 * @author Keith Donald
 * @author Jeremy Grelle
 * @author Sebastien Deleuze
 * @since 3.0
 */
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
		registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
		registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
		registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
		registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
	}
}
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	// 获取一个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
	// 在它里面维护的parser集合中找到
	// 与该标签对应的parser,由该parser来执行解析
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

NamespaceHandler的初始化:在DefaultNamespaceHandlerResolver的getHandlerMappings方法实现。

在resolve方法中调用getHandlerMappings方法。

/**
 * Load the specified NamespaceHandler mappings lazily.
 */
private Map<String, Object> getHandlerMappings() {
	Map<String, Object> handlerMappings = this.handlerMappings;
	if (handlerMappings == null) {
		synchronized (this) {
			handlerMappings = this.handlerMappings;
			if (handlerMappings == null) {
				if (logger.isTraceEnabled()) {
					logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
				}
				try {
					Properties mappings =
							PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
					if (logger.isTraceEnabled()) {
						logger.trace("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;
}
  1. 从META-INF/spring.handlers文件加载键值对,并缓存在类型为ConcurrentHashMap的handlerMappings中;
  2. 注意这里并没有初始化NamespaceHandler,即handlerMappings的value还是String类型。

NamespaceHandler包含的parsers的初始化:在resolve方法中进行懒加载初始化。

  /**
   * Locate the {@link NamespaceHandler} for the supplied namespace URI
   * from the configured mappings.
   * @param namespaceUri the relevant namespace URI
   * @return the located {@link NamespaceHandler}, or {@code null} if none found
   */
  @Override
  @Nullable
  public NamespaceHandler resolve(String namespaceUri) {
      // 懒加载NamespaceHandler的handlerMappings
  	Map<String, Object> handlerMappings = getHandlerMappings();
  	Object handlerOrClassName = handlerMappings.get(namespaceUri);
  	if (handlerOrClassName == null) {
  		return null;
  	}
  	// 不是第一次调用,则已经是NamespaceHandler类型了,可以直接返回
  	else if (handlerOrClassName instanceof NamespaceHandler) {
  		return (NamespaceHandler) handlerOrClassName;
  	}
  	// 第一次调用,由上面分析可知:
  	// 刚开始从META-INF/spring.handlers
  	// 读出时,handlerMappings的value是字符串
  	else {
  		String className = (String) handlerOrClassName;
  		try {
  		// 加载NamespaceHandler
  			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);
  			// 调用init方法完成parsers的初始化
  			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);
  		}
  	}
  }
  protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
  }

NamespaceHandler的init方法实现:各个NamespaceHandler接口实现类,在init方法中注册xml的标签和Parser之间的映射关系:如下为context标签的名称空间处理器ContextNamespaceHandler:

/**
 * {@link org.springframework.beans.factory.xml.NamespaceHandler}
 * for the '{@code context}' namespace.
 *
 * @author Mark Fisher
 * @author Juergen Hoeller
 * @since 2.5
 */
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		// <context:component-scan />
    	registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}
}

插件机制拓展支持

如果需要开发一个插件并自定义标签,然后融入到Spring容器中,则可以在自身插件项目中,基于NamespaceHandler来实现,如在Dubbo项目中,就是利用了Spring的这个机制来容器到Spring框架的

基本步骤包括:

  1. 自定义xsd标签定义,并添加到插件项目的META-INF目录中,路径类似于一个普通pacakage下面的一个类;
  2. 实现BeanDefinitionParser接口,定义标签的处理逻辑;
  3. 实现NamespaceHandler接口,一般继承Spring的NamespaceHandlerSupport即可。在init方法中,使用registerBeanDefinitionParser方法配置标签名称和BeanDefinitionParser实现类的映射关系。
  4. 在META-INF/spring.schemas文件中,定义xsd文件全限定名与一个在applicationContext.xml文件中可以配置的命名空间url的映射;
  5. 在META-INF/spring.handlers文件中,定义以上命名空间url和该NamespaceHandler实现类的映射。

到此这篇关于spring的applicationContext.xml文件与NamespaceHandler解析的文章就介绍到这了,更多相关applicationContext与NamespaceHandler解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文