org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
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)) { parseDefaultElement(ele, delegate); } else { //解析自定义标签 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { //根据自定义标签的命名空间来确定namespaceUri String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } //根据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; } //具体的解析过程 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
来看下如何通过namespaceUrl获取到Handler的具体过程
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
public NamespaceHandler resolve(String namespaceUri) { //获取所有的mapping Map<String, Object> handlerMappings = getHandlerMappings(); //根据uri获取对应的命名空间处理器 Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { //反射生成自定义解析xml处理器对象 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(); //解析完后把命名空间和命名空间处理器放入map中 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); } } }
注意这里有个toString的方法,idea debug的时候回调用起来,从而进行读取配置文件
@Override public String toString() { return "NamespaceHandlerResolver using mappings " + getHandlerMappings(); }
先看构造方法:
public DefaultNamespaceHandlerResolver() { this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION); }
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader, String handlerMappingsLocation) { Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null"); this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); this.handlerMappingsLocation = handlerMappingsLocation; }
原来解析的时候会去读取类路径下的META-INF/spring.handlers的配置文件,然后把所有属性通过k-v的形式存入properties
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings
执行完该方法后会把所有类路径下的文件解析成k-v格式然后存入map中,共后续使用
下面以具体的列子来分析:
<context:component-scan base-package="com.aa"></context:component-scan>
1.找到xsd: spring-context.xsd
2.在类路径下找到 META-INF/spring.handlers
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
3.根据命名空间获取对应的xml解析处理器
4.进行回调,解析,执行init()方法
public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); 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()); } } 5.看看具体的解析过程 registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); public BeanDefinition parse(Element element, ParserContext parserContext) { //获取包路径 String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // Actually scan for bean definitions and register them. ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); //解析包路径下的所有class文件,判断class是否有@Component的注解,有的话,放入beanDefinitionMap中,将其注入为 //spring bean Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }