您的位置:首页 > 编程语言 > Java开发

借零配置类分析struts2的插件机制是怎么实现的。

2014-07-17 12:25 288 查看
struts2的零配置是真正的零配置,那种使用注解的方式,我认为那不是零配置,只是换了种形式而已。那么作为struts2的插件之一,convention组件又是如何加入,或者说是像个USB盘一样插入struts2的这个电脑呢?我们知道使用USB的前提是电脑预留了这个插口(接口),而这个接口将来具体是插入USB盘呢,还是其他的手机我电脑是不关心的。以下我们将以问题的形式来完成分析:

      1、作为插件,convention是如何到无缝插入的?

            跟踪struts2的源码,在DefaultConfiguration中reloadContainer方法中,有这样一段:

            // Then process any package providers from the plugins

            Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);

            for (String name : packageProviderNames) {

                PackageProvider provider = container.getInstance(PackageProvider.class, name);

                provider.init(this);

                provider.loadPackages();

                packageProviders.add(provider);

            }

            其中container.getInstanceNames是从整个XWork容器中去获取实现了PackageProvider接口的类的所有名字,比如配置如下:

  <bean type="com.opensymphony.xwork2.UnknownHandler" name="convention" class="org.apache.struts2.convention.ConventionUnknownHandler"/>

  <bean type="org.apache.struts2.convention.ActionConfigBuilder" name="convention" class="org.apache.struts2.convention.PackageBasedActionConfigBuilder"/>

  <bean type="org.apache.struts2.convention.ActionNameBuilder" name="convention" class="org.apache.struts2.convention.SEOActionNameBuilder"/>

  <bean type="org.apache.struts2.convention.ResultMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultResultMapBuilder"/>

  <bean type="org.apache.struts2.convention.InterceptorMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultInterceptorMapBuilder"/>

  <bean type="org.apache.struts2.convention.ConventionsService" name="convention" class="org.apache.struts2.convention.ConventionsServiceImpl"/>

  <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.packageProvider"
class="org.apache.struts2.convention.ClasspathPackageProvider"/>

  <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.containerProvider"
class="org.apache.struts2.convention.ClasspathConfigurationProvider"/>

  <constant name="struts.convention.actionConfigBuilder" value="convention"/>

  <constant name="struts.convention.actionNameBuilder" value="convention"/>

  <constant name="struts.convention.resultMapBuilder" value="convention"/>

  <constant name="struts.convention.interceptorMapBuilder" value="convention"/>

  <constant name="struts.convention.conventionsService" value="convention"/>

  不要奇怪“怎么bean的名字都一样啊?“,在xWork的世界里一个具体的实现bean是由接口和name两个属性共同决定的。也就是说,通过container.getInstance这个方法就能拿到所有实现了PackageProvider这个接口的实现类的名字,然后后边的for循环逐一拿到所有PackageProvider这个接口的所有实现,这就是扩展的关键。也就是说,无论PackageProvider有多少个实现,只要你保证name属性不冲突,就能加入到xWork容器中,并且被调用。要做到这点太简单了,分为以下步骤:

1)实现我们的PackageProvider类;

        2)配置到struts.xml中,或者是struts-plugin.xml中即可,当然了name属性不能和框架中该PackageProvider既有的实现冲突,否则会报错。

而convention插件正是用这种方式把自己的零配置逻辑加入进去的。这就是整个convention插件的入口。

2、说了半天,那么PackageProvider是做什么用的呢?

              这个类是XWork配置文件处理接口,正是基于以上的机制,Struts才会有五花八门的配置文件,既可以用xml,也可以用properties,最后又加入了零配置的插件。

        3、以上的方式最起码有以下两点做的非常好,最起码在设计面向组件开发的框架里可以借鉴。

      1)抽取接口+注册的方式,当然了这个注册需要有个容器,XWork提供了这个容易,这个和Spring的设计思想一致。是符合开闭口原则的典型设计;

              2)采用”兼容并包“的方式,比如其中的for循环的方式,当然了这个主要是设计者的考虑了,如果设计者不打算留给扩充余地,肯定就不会用这个方式了;

        3、那么这个是如何做到的呢?为什么我们常常不能一下子想到的呢?

             这个其实没有什么,要做到这点,个人觉得有以下方式:

             1)丰富的框架设计经验,能站在很高的程度,对框架的各个关键节点的地方提出扩展机制,比如采用以上的”提取接口+注册“的方式。

             2)在框架演化过程中,逐渐意识到这个扩展点的重要性,从而不断重构设计和代码。当然了,在做完这件事情后必须要总结,这样逐步地我们就具有了第一点中提到的眼光。这个从量变到质变的过程是非常重要的,是常常被我们程序员忽略的问题。我们常常只羡慕强人,却不去认真想强人是如何成为强人的。只注意了别人手中的鱼,而忽略了他捕鱼的过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: