springframework源代码阅读杂记(2)---spring.handlers文件介绍
在Spring的使用过程中,会使用到各种标签元素,那么这些标签元素是怎么解析的呢?这个就与SPring的核心组件相关了。
springframework作为spring框架的最核心组件,提供了IOC和AOP的功能,
springframework中最核心的五的组件是SpringAop、SpringBean、SpringContext、SpringAspect和SpringCore。
SpringAop、SpringBean、SpringContext都包含了spring.handlers文件,表明他们能解析的xml元素。
spring-aop的spring.handlers文件如下:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
spring-bean如下:
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
SpringContext如下:
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
spring-bean作为默认的配置根元素,不需要特别配置,这个从解析代码中就可以看出。
我们以XML解析为例来看下:
ApplicationContext bc = new ClassPathXmlApplicationContext("./resources/spring-common.xml");
spring-common.xml的定义如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <context:property-placeholder location="classpath:foo.properties" /> <bean id="person" class="com.nuaa.SpringXMLConfig.Person"> <property name="name" value="helloworldwangjy"></property> <property name="year" value="100"></property> </bean> </beans>
new ClassPathXmlApplicationContext("./resources/spring-common.xml") 最终会调用DefaultBeanDefinitionDocumentReader的parseBeanDefinitions函数。
主要的解析函数如下:
DefaultBeanDefinitionDocumentReader
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); } }
流程图如下:
在BeanDefinitionParserDelegate中存在函数如下:
public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); } public boolean isDefaultNamespace(Node node) { return isDefaultNamespace(getNamespaceURI(node)); }
BEANS_NAMESPACE_URI的定义如下:
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
从代码可以看出,如果是isDefaultNamespace返回true,就进入函数parseDefaultElement(ele, delegate),如果不是则进入函数delegate.parseCustomElement(ele);
parseDefaultElement函数中,则分别读取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); } }
delegate.parseCustomElement(ele)函数如下:
public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); 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)); }
首先获取元素的nameSpaceUri,然后根据nameSpaceUri获取指定的NamespaceHandler进行解析,
譬如property-placeholder元素,其配置如下:
<context:property-placeholder location="classpath:foo.properties" />
namespaceUri的值就是 http://www.springframework.org/schema/context
this.readerContext.getNamespaceHandlerResolver()获取到的是NamespaceHandlerResolver的实现类,为DefaultNamespaceHandlerResolver。
DefaultNamespaceHandlerResolver中包含了一个handlerMappings,
/** Stores the mappings from namespace URI to NamespaceHandler class name / instance */ private volatile Map<String, Object> handlerMappings;
handlerMappings其中存储了所有的nameSpaceUri及其对应的NamespaceHandler。
我们把 handlerMappings内容打印如下
"http://www.springframework.org/schema/aop" -> "org.springframework.aop.config.AopNamespaceHandler"
"http://www.springframework.org/schema/cache" -> "org.springframework.cache.config.CacheNamespaceHandler"
"http://www.springframework.org/schema/task" -> "org.springframework.scheduling.config.TaskNamespaceHandler"
"http://www.springframework.org/schema/p" -> "org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler"
"http://www.springframework.org/schema/util" -> "org.springframework.beans.factory.xml.UtilNamespaceHandler"
"http://www.springframework.org/schema/lang" -> "org.springframework.scripting.config.LangNamespaceHandler"
"http://www.springframework.org/schema/c" -> "org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler"
"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/context的对应的解析类是org.springframework.context.config.ContextNamespaceHandler。获取到后就由org.springframework.context.config.ContextNamespaceHandler解析对应的元素。