在了解自定义标签原理前,先看下如何使用自定义标签:http://blog.csdn.net/humanmonkey/article/details/72790150
在如何使用自定义标签中可以关注到,最重要的是NamespaceHandlerSupport、AbstractSingleBeanDefinitionParser、spring.handlers和spring.schemas这四个东东。怎么通过NamespaceHandlerSupport.init()、AbstractSingleBeanDefinitionParser.doParse、spring.handlers和spring.schemas来实现的呢?spring对标签的解析流程如下:
Step 1: 将 xml 文件解析成 Dom 树。将 xml 文件解析成 dom 树的时候,需要 xml 标签定义 schema 来验证文件的语法结构。 Spring 约定将所有的 shema 的虚拟路径和真实文件路径映射定义在 classpath 的在 META-INF/spring.schemas 下面。在容器启动时 Spring 会扫描所有的 META-INF/spring.schemas 并将映射维护到一个 map 里。
Step 2: 将 dom 树解析成 BeanDifinition ,将定义 bean 的标签和 xml 定义解析成 BeanDefinition 的过程。如果是默认的 bean 标签, spring 会直接进行解析。而如果不是默认的 bean 标签,包括自定义和 spring 扩展的 <aop> 、 <p> 、 <util> 等标签,则需要提供专门的 xmlparser 来处理。 parser由自己定义和编写,并通过handler注册到容器。Spring 约定了 META-INF/spring.handlers 文件,在这里面定义了标签命名空间和handler 的映射。容器起来的时候会加载 handler , handler 会向容器注册该命名空间下的标签和解析器。在解析的自定义标签的时候, spring 会根据标签的命名空间和标签名找到一个解析器。由该解析器来完成对该标签内容的解析,并返回一个 BeanDefinition 。
以下是源码的实现:
1、 加载 spring.shemas: 在PluggableSchemaResolver.Java里实现,解析namespace后放入map中
public class PluggableSchemaResolver implements EntityResolver { /***定义schema location的映射文件路径***/
public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas"; private static final Log logger = LogFactory.getLog(PluggableSchemaResolver.class); private final ClassLoader classLoader; private final String schemaMappingsLocation;
/** 存储schema*/ private volatile Map<String, String> schemaMappings; public PluggableSchemaResolver(ClassLoader classLoader) { this.classLoader = classLoader; this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION; } public PluggableSchemaResolver(ClassLoader classLoader, String schemaMappingsLocation) { Assert.hasText(schemaMappingsLocation, "'schemaMappingsLocation' must not be empty"); this.classLoader = classLoader; this.schemaMappingsLocation = schemaMappingsLocation; } @Override public InputSource resolveEntity(String publicId, String systemId) throws IOException { if (logger.isTraceEnabled()) { logger.trace("Trying to resolve XML entity with public id [" + publicId + "] and system id [" + systemId + "]"); } if (systemId != null) { String resourceLocation = getSchemaMappings().get(systemId); if (resourceLocation != null) { Resource resource = new ClassPathResource(resourceLocation, this.classLoader); try { InputSource source = new InputSource(resource.getInputStream()); source.setPublicId(publicId); source.setSystemId(systemId); if (logger.isDebugEnabled()) { logger.debug("Found XML schema [" + systemId + "] in classpath: " + resourceLocation); } return source; } catch (FileNotFoundException ex) { if (logger.isDebugEnabled()) { logger.debug("Couldn't find XML schema [" + systemId + "]: " + resource, ex); } } } } return null; }
/**完成schema的解析存储*/ private Map<String, String> getSchemaMappings() { if (this.schemaMappings == null) { synchronized (this) { if (this.schemaMappings == null) { if (logger.isDebugEnabled()) { logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]"); } try { Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded schema mappings: " + mappings); } Map<String, String> schemaMappings = new ConcurrentHashMap<String, String>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings); this.schemaMappings = schemaMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex); } } } } return this.schemaMappings; } }
2、是否选择默认handler:通过delegate.isDefaultNamespace(root)来判断是否是默认的namespaceuri,默认是http://www.springframework.org/schema/beans
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { 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)) {//解析默认命名空间,通过判断namespace 是否等于http://www.springframework.org/schema/beans来判断 parseDefaultElement(ele, delegate); } else {//解析自定义命名空间 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }}
3、选择自定义handler:调用自定义handler的init方法
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
/**通过namespace中选择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; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {}
public NamespaceHandler resolve(String namespaceUri) {
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);//调用自定义handler的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); } }
4、调用自定义parser
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
@Override 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 = null; if (shouldParseNameAsAliases()) { String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } }
//进行bean注册 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; }}
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
@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<?> beanClass = getBeanClass(element); if (beanClass != null) { builder.getRawBeanDefinition().setBeanClass(beanClass); } else { 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); }
//调用自定义parser的doparse方法进行解析标签 doParse(element, parserContext, builder); return builder.getBeanDefinition(); }}
5、bean注册
请看4中注释
ok,通过以上就可以清楚知道spring底层是如何运行的,从xml解析到调用NamespaceHandlerSupport中init方法,紧接着调用AbstractSingleBeanDefinitionParser中的doParse方法进行解析,到最后如何注册成bean