SpringExt 源码学习
2016-08-16 15:20
459 查看
大致了解SpringExt
Spring Schema提供了我们便捷的初始化bean的方法,我们不需要再去写构造器注入或者属性注入直接使用类似的如下配置代码即可完成bean的初始化<resource-loading id="resourceLoadingService" xmlns="http://www.alibaba.com/schema/services/resource-loading"> <resource pattern="/file"> <file-loader basedir="${user.home}" /> </resource> <resource pattern="/webroot"> <webapp-loader /> </resource> </resource-loading>
但是Spring Schema是不具有拓展性的,我们不能随意添加一个
database-loader,对比以上代码
<resource-loading id="resourceLoadingService" xmlns="http://www.alibaba.com/schema/services/resource-loading"> <resource pattern="/file"> <file-loader basedir="${user.home}" /> </resource> <resource pattern="/webroot"> <webapp-loader /> </resource> <resource pattern="/db"> <database-loader connection="jdbc:mysql:mydb" /> </resource> </resource-loading>
于是SpringExt帮助我们通过定义
拓展点(ConfigurationPoint)和声明
贡献(Contribution)的方式实现我们的动态拓展功能:
<resource-loading id="resourceLoadingService" xmlns="http://www.alibaba.com/schema/services" xmlns:loaders="http://www.alibaba.com/schema/services/resource-loading/loaders"> <resource pattern="/file"> <loaders:file-loader basedir="${user.home}" /> </resource> <resource pattern="/webroot"> <loaders:webapp-loader /> </resource> <resource pattern="/db"> <loaders:database-loader connection="jdbc:mysql:mydb" /> </resource> </resource-loading>
同时SpringExt提供将远程的xsd文件存储至本地的功能
以上的例子请详细阅读Webx的文档:http://www.openwebx.org/docs/Webx3_Guide_Book.html#webx.overview.springext
Spring IOC 初始化
spring在DefaultBeanDefinitionDocumentReader.parseBeanDefinitions方法中会根据当前的element的namespaceUri判断是否是Spring定义的还是用户自定义的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); } }
SpringExt就是借助自定义区进行解析
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)); }
实现自定义的基本流程
1.编写xsd文件截取了一段
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsd:schema xmlns="http://www.springframework.org/schema/tool" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.springframework.org/schema/tool" elementFormDefault="qualified"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/> ... <xsd:complexType name="registersScopeType"> <xsd:attribute name="name" type="xsd:string" use="required"> <xsd:annotation> <xsd:documentation><![CDATA[ Defines the name of a custom bean scope that the annotated type registers, e.g. "conversation". Such a scope will be available in addition to the standard "singleton" and "prototype" scopes (plus "request", "session" and "globalSession" in a web application environment). ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> </xsd:complexType> </xsd:schema>
2.META-INF/spring.schemas 文件中建立namespace.xsd 与xsd 文件实际路径的映射
也就是类似于
http://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
3.编写NamespaceHandler,并在META-INF/spring.handlers建立Namespace与NamespaceHandler的联系
http://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
4.实现若干BeanDefinitionParser类,用于解析Xml元素,生成BeanDefinition。BeanDefinitionParser需要在NamespaceHandler中注册。
以上步骤也可以继承NamespaceHandlerSupport类,这个抽象类完成了NamespaceHandler的parse功能,也提供了注册BeanDefinitionParser的方法,是Webx使用的。
Webx的初始化
首先Webx重写了XmlWebApplicationContext。public class XmlWebApplicationContext extends org.springframework.web.context.support.XmlWebApplicationContext implements ResourceLoadingExtendable
同时实现了父类的initBeanDefinitionReader实现加入SpringExt相关的内容。一下这部分代码是主要的加载
拓展点和
捐赠的过程
public void addConfigurationPointsSupport() { if (skipValidation) { reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE); reader.setNamespaceAware(true); // 为了添加Configuration Point支持,namespace是必须打开的。 reader.setDocumentReaderClass(DocumentReaderSkippingValidation.class); // 对beans中的参数提供默认值 log.warn( "XSD validation has been disabled according to the system property: -D{}. Please be warned: NEVER skipping validation in Production Environment.", PROPERTY_SKIP_VALIDATION); } ResourceLoader resourceLoader = reader.getResourceLoader(); if (resourceLoader == null) { resourceLoader = new DefaultResourceLoader(); } ClassLoader classLoader = resourceLoader.getClassLoader(); // schema providers SpringExtSchemaSet schemas = new SpringExtSchemaSet(classLoader); // default resolvers EntityResolver defaultEntityResolver = new ResourceEntityResolver(resourceLoader); NamespaceHandlerResolver defaultNamespaceHandlerResolver = new DefaultNamespaceHandlerResolver(classLoader); // new resolvers EntityResolver entityResolver = new SchemaEntityResolver(defaultEntityResolver, schemas); NamespaceHandlerResolver namespaceHandlerResolver = new ConfigurationPointNamespaceHandlerResolver(schemas.getConfigurationPoints(), defaultNamespaceHandlerResolver); reader.setEntityResolver(entityResolver); reader.setNamespaceHandlerResolver(namespaceHandlerResolver); }
这部分有三个主要的步骤:
初始化的流程全部,包括注册
拓展点和
捐赠:
SpringExtSchemaSet schemas = new SpringExtSchemaSet(classLoader);
定义新的EntityResolver
EntityResolver entityResolver = new SchemaEntityResolver(defaultEntityResolver, schemas);
同时定义新的NamespaceHandlerResolver并使其能够取得SpringExt的NamespaceHandler的代码
NamespaceHandlerResolver namespaceHandlerResolver = new ConfigurationPointNamespaceHandlerResolver(schemas.getConfigurationPoints(), defaultNamespaceHandlerResolver);
SpringExtSchemaSet
别看只有一行构造方法,但是跟进去会发现别有洞天!SchemaSet将一组
Schemas整合在一起的集合。那么是哪些
Schemas呢?
public SpringExtSchemaSet(ClassLoader classLoader) { this(new ConfigurationPointsImpl(classLoader), new SpringPluggableSchemas(classLoader)); }
ConfigurationPointsImpl负责SpringExt的拓展特性的加载,而SpringPluggableSchemas则是将Spring所支持的
META-INF/spring.schemas中定义的schemas移到本地服务器。这两者都集成自
Schemas接口,这个接口只有一个方法就是获得一个Map
SchemaEntityResolver
主要是根据systemId获得其Schema的InputStream的过程,可对比Spring的DTD或者XSD的读取方法public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { log.trace("Trying to locate XML entity {} as configuration points schema.", systemId); Schema schema = schemas.findSchema(systemId); if (schema == null) { if (defaultEntityResolver != null) { return defaultEntityResolver.resolveEntity(publicId, systemId); } else { return null; } } log.debug("Found XML schema for systemId {}: {}", systemId, schema); return new InputSource(schema.getInputStream()); }
ConfigurationPointNamespaceHandlerResolver
ConfigurationPointImpl继承NamespaceHandlerSupport,主要是根据Namespace获得ConfigurationPointpublic NamespaceHandler resolve(String namespaceUri) { ConfigurationPoint cp = cps.getConfigurationPointByNamespaceUri(namespaceUri); if (cp != null) { return cp.getNamespaceHandler(); } else if (defaultResolver != null) { return defaultResolver.resolve(namespaceUri); } else { return null; } }
NamespaceHandlerSupport已经实现
parse方法,ConfigurationPoint包含了
拓展点的所有
捐赠,根据namespaceUri即可获得其具体的捐赠,也就是具体的BeanDefinitionParser
相关文章推荐
- spring学习笔记:Spring IOC容器,Spring源码
- spring学习笔记之AbstractController源码解读
- Spring IOC核心源码学习
- 学习spring源码
- (精)Spring IOC核心源码学习III:bean标签和自定义标签实现原理
- 学习Spring 附带源码jpetstore 一 安装配置篇
- spring源码学习笔记-初始化(三) registerBeanPostProcessors
- spring源码学习笔记-初始化(五)-MessageSource/事件监听器
- spring源码学习笔记-初始化(四)-PostProcessor
- Spring源码学习-含有通配符路径解析(上) 推荐
- spring学习笔记之handler mapping源码解读
- Spring源码学习(一)------ IoC
- Spring源码学习(二)------ AOP
- spring源码学习笔记-初始化(六)-完成及异常处理
- spring源码学习笔记-初始化(一)-概览
- spring学习笔记之DispatcherServlet源码解读
- Spring源码学习(二)------ AOP
- Spring源码学习(一)------ IoC
- Spring源码学习-容器初始化之FileSystemXmlApplicationContext(一)构造函数 推荐
- spring源码学习笔记-初始化(二) PostProcessor