SpringExt 扩展原理

来源:互联网 发布:windows 安全配置基线 编辑:程序博客网 时间:2024/05/20 18:45

         这篇文章是基于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无法解析。(多了db)

          

<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文件即可。



0 0
原创粉丝点击