spring源码剖析(四)自定义标签解析流程
2015-12-01 10:39
706 查看
解析总流程
自定义标签解析入口
让我们先看BeanDefinitionParserDelegate类的parseCustomElement方法:public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } //containingBd为父类bean,对顶层元素的解析应设置为null public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); //根据命名空间找到对应的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)); }
提取自定义标签处理器
跟踪this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);进入DefaultNamespaceHandlerResolver中的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 */ public NamespaceHandler resolve(String namespaceUri) { //获取所有已经配置的handler映射 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); 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的初始化方法 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); } } }
回忆上一篇的自定义标签使用中的MyNamespaceHandler便可以发现,其实上面的方法就是初始化了MyNamespaceHandler,然后调用了他的init()方法
/** * * @author Administrator */ public class MyNamespaceHandler extends NamespaceHandlerSupport { /* (non-Javadoc) * @see org.springframework.beans.factory.xml.NamespaceHandler#init() */ @Override public void init() { registerBeanDefinitionParser("user", new UserBeanDefinitionParser()); } }
让我们在看看spring是如何获取handler映射的,查看getHandlerMappings()方法
/** * Load the specified NamespaceHandler mappings lazily. */ private Map<String, Object> getHandlerMappings() { //如果没有被缓存,则开始进入缓存 if (this.handlerMappings == null) { synchronized (this) { if (this.handlerMappings == null) { try { //this.handlerMappings在构造函数已被初始化为META-INF/Spring.handlers 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()); //将properties文件合并到Map格式的handlerMappings中 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; }
标签解析
得到了解析器和分析的元素侯,Spring就可以将解析工作委托给自定义解析器去解析了让我们回到BeanDefinitionParserDelegate的handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));中
进入NamespaceHandlerSupport中的parse方法
/** * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is * registered for that {@link Element}. */ public BeanDefinition parse(Element element, ParserContext parserContext) { //寻找解析器,并进行解析操作 return findParserForElement(element, parserContext).parse(element, parserContext); } /** * Locates the {@link BeanDefinitionParser} from the register implementations using * the local name of the supplied {@link Element}. */ private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { //获取元素名称,也就是<myname:user 中的user,此时localname为user String localName = parserContext.getDelegate().getLocalName(element); //根据user找到对应的解析器也就是在 //registerBeanDefinitionParser("user", new UserBeanDefinitionParser());注册的解析器 BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
让我们再跟踪到AbstractBeanDefinitionParser 的parse()方法
public final BeanDefinition parse(Element element, ParserContext parserContext) { AbstractBeanDefinition definition = parseInternal(element, parserContext); if (definition != null && !parserContext.isNested()) { try { String id = resolveId(element, definition, parserContext); if (!StringUtils.hasText(id)) { parserContext.getReaderContext().error( "Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element); } String[] aliases = new String[0]; String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } //将AbstractBeanDefinition转换成BeanDefinitionHolder BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); registerBeanDefinition(holder, parserContext.getRegistry()); if (shouldFireEvents()) { //需要通知监听器进行处理 BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder); postProcessComponentDefinition(componentDefinition); parserContext.registerComponent(componentDefinition); } } catch (BeanDefinitionStoreException ex) { parserContext.getReaderContext().error(ex.getMessage(), element); return null; } } return definition; }
虽然说是对自定义配置文件的解析,但是我们可以看到,在这个函数中大部分的大马士用来处理将解析后的AbstractBeanDefinition转换为BeanDefinitionHolder并注册的功能,而真正去做解析的事情委托了给parseInternal,真是这句代码调用了我们的自定义解析函数。在parseInternal中,并不是直接调用自定义的doParse函数,而是惊醒了一些列的数据准备,包括对beanClass,scope,lazyInit等属性的准备。
接下来,让我们看看parseInternal方法,先跟踪到AbstractSingleBeanDefinitionParser
/** * Creates a {@link BeanDefinitionBuilder} instance for the * {@link #getBeanClass bean Class} and passes it to the * {@link #doParse} strategy method. * @param element the element that is to be parsed into a single BeanDefinition * @param parserContext the object encapsulating the current state of the parsing process * @return the BeanDefinition resulting from the parsing of the supplied {@link Element} * @throws IllegalStateException if the bean {@link Class} returned from * {@link #getBeanClass(org.w3c.dom.Element)} is {@code null} * @see #doParse */ @Override protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); String parentName = getParentName(element); if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } //获取自定义标签中的class,此时会调用自定义解析器,如UserBeanDefinitionParser中的getBeanClass方法 Class<?> beanClass = getBeanClass(element); if (beanClass != null) { builder.getRawBeanDefinition().setBeanClass(beanClass); } else { //若子类没有重写getBeanClass方法则尝试检查子类是否重写getBeanClassName方法 String beanClassName = getBeanClassName(element); if (beanClassName != null) { builder.getRawBeanDefinition().setBeanClassName(beanClassName); } } builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); if (parserContext.isNested()) { // Inner bean definition must receive same scope as containing bean. builder.setScope(parserContext.getContainingBeanDefinition().getScope()); } if (parserContext.isDefaultLazyInit()) { // Default-lazy-init applies to custom bean definitions as well. builder.setLazyInit(true); } doParse(element, parserContext, builder); return builder.getBeanDefinition(); }
相关文章推荐
- Android Studio启动时卡在Fetching Android SDK 以及导入Eclipse工程慢的解决方法
- Java读书笔记十二(Java中的代码块)
- Java字符串性能优化
- Java系列:国际化(zz)
- java虚拟机
- Java数组/集合性能优化
- java设计模式之代理模式
- Eclipse插件开发中遇到的一些错误处理
- JAVA--继承
- eclipse无法启动
- 我碰到的Java heap space问题
- java泛型通配符
- javaSwing使用自定义字体
- Struts2的开发步骤,简单明了
- java自带的MD5\Sha1\Base64加密和Bse64解密
- Java 代码中如何预防空指针异常
- Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
- 【java基础】运行jar应用程序引用其他jar包的四种方法
- struts2 filter版本
- 个人学习Java的真实经验