`
paddy.w
  • 浏览: 497499 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

SpringExt 扩展原理

 
阅读更多
        这篇文章是基于webx框架官方文档整理的。具体的请参见webx官方文档。

        首先先弄明白在面向对象的设计中比较核心的一个原则——OCP(Open-Closed Principle),也就是开闭原则。
        最早描述OCP的是OCP原则的提出者Bertrand Meyer,他在他的著作《Object Oriented Software Construction》中提出了OCP原则:“Software entities should be open for extension,but closed for modification”,也就是“软件实体应当对扩展开放,对修改关闭”。简单点说就是如果原有功能没有什么问题而需要扩展新的功能,那么就应该在不修改原有代码的基础上进行功能的扩展。
        下面将要讲到的SpringExt就是为了符合OCP原则而对Spring的一种扩展。

        SpringExt装配服务
        webx中有一个非常有用的ResourceLoadingService,它可以从各种输入源中(比如FileSystem、Classpath、Webapp等等)读取源文件的一种服务。下面就以这个服务为例来说明一下SpringExt是如何对Spring进行扩展使其符合OCP原则。

        ResourceLoadingService的结构如下所示

        下面我们以这个为例来看一下Spring Beans是如何装载Resource Loading服务的。
        Spring2.0之前只能使用如下的xml配置来进行装载
<bean id="resourceLoadingService" class="com.alibaba...ResourceLoadingServiceImpl">
    <property name="mappings">
        <map>
            <entry key="/file" value-ref="fileLoader" />
            <entry key="/webroot" value-ref="webappLoader" />
        </map>
    </property>
</bean>

<bean id="fileLoader" class="com.alibaba...FileResourceLoader">
    <property name="basedir" value="${user.home}" />
</bean>

<bean id="webappLoader" class=" com.alibaba...WebappResourceLoader" />

        上面的配置如果有点Spring基础的都应该看的懂,典型的IOC。ResourceLoadingServiceImpl并不依赖FileResourceLoader和WebappResourceLoader,它只依赖它们的接口ResourceLoader。至于如何创建FileResourceLoader、WebappResourceLoader、需要提供哪些参数,这些都由spring来负责。
        Spring本身并不了解如何创建ResourceLoader对象、用哪些参数、如何注入等等。但并不是说没有人关注这些。这些事情由装配者(程序员)来解决,也就是写这些配置文件的人。
        先定义两个角色:服务提供者、服务使用者。ResourceLoadingService的作者是服务提供者,也就是写ResourceLoadingService服务的人。使用ResourceLoadingService的人就是服务使用者,服务使用者利用Spring吧ResourceLoadingService和ResourceLoader装配在一起。

        这种配置文件的方式可能会带来比较一些问题。
        1、没有检验机制,只能在运行时发现错误。
        2、除了阅读源代码,无从得知更多的约束条件。
        3、如果服务的实现改变了,这个配置文件可能会失败。因为从bean的class属性可以看出,bean是直接依赖于具体的实现的。

        Spring Schema
        关于Xml Schema可以参考http://www.w3school.com.cn/schema/index.asp,这里不再赘述。
        Spring2.0之后可以用Spring Schema改写为下面:
<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>

        首先说一下这个配置文件的优点。
        1、简洁易读。
        2、可验证。
        3、可以包含约束条件。
        4、服务的细节对装配者隐藏。这也是最重要的一点,从配置文件中可以看出,并没有引用具体的实现类。那么当服务的实现类被改变时,只要Xml Schema没有变,Spring的配置就不会受到影响。
        虽然配置文件中没有体现出具体的实现,但是Spring需要知道这些内容。那Spring是怎么知道的?
        每个schema都会有一个解释器。解释器是有服务的开发者提供的。解释器会将符合标准的xml schema转换成Spring能读懂的beans定义。

        上面这个图就很清晰了。服务的使用者不知道API的具体实现,这样的三层结构相当于减少了耦合。
         但是,Spring Schema也存在一个问题,就是无法扩展。比如,下面的配置文件就是错误的,因为Spring Schema无法解析。
<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>

        我们需要添加新的加载器,但是schema并没有预料到这种情况,所以schema中并没有这方面的信息,因此无法解析上面的配置文件。如果我们要求Spring Schema来解析新的加载器,那必须要修改Schema的定义文件。很显然,这违背了OCP原则。

        SpringExt Schema
        SpringExt Schema可以将Spring Schema进行进一步的更改:
<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>

        上面的配置文件就可以正确解析,但是并没有对原有的schema做修改。仔细对比一下这两个配置文件,可以发现后一个配置文件中出现了两个xmlns,这也导致了标签的相关书写也不太一样,比如loaders:file-loader。
       
        SpringExt Schema的原理
        下面是resource-loading.xsd的片段:
<xsd:element name="resource" type="ResourceLoadingServiceResourceType">
<xsd:complexType name="ResourceLoadingServiceResourceType">
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:any namespace="http://www.alibaba.com/schema/services/resource-loading/loaders" /> 
    </xsd:choice>
    <xsd:attribute name="pattern" type="xsd:string" use="required" />
</xsd:complexType>

        熟悉schema规则的很容易明白SpringExt是如何进行扩展的,关键在<xsd:any>这个标签。
        总结性的讲,在上面的例子中,Spring Schema中定义了一个namespace,而SpringExt Schema定义了两个namespace。这就是关键所在,SpringExt把需要扩展的schema进行了分离,如果我们需要进行扩展,那么添加一个新的xsd文件即可。
  • 大小: 211.7 KB
  • 大小: 300.6 KB
  • 大小: 352.4 KB
  • 大小: 414.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics