開元框架HiveMind 下一代軟件流行框架--邵京國

今天HiveMind 1.0 的final版本出來了, 看了看他的examples代碼。 有了IoC(DI)的感覺之後再看這些代碼, 越看感覺越清晰。 實現一個IoC的容器本身沒什麼可說的, 現在就以他自帶的example爲例,來看看HiveMind在這方面的實現方法。

example程序是一個四則運算的類,基本思想是將加減乘除都做成接口,用不同的方式實現;計算器(Caculator)繼承了加減乘除接口,在運行過程中,具體的加減乘除操作類通過HiveMind的配置注入到CaculatorImpl中,當然CaculatorImpl也是通過Caculator接口通過工廠產生出來的,以下是他的具體代碼:

 double arg0 = Double.parseDouble(args[0]);
        double arg1 = Double.parseDouble(args[1]);

        Registry registry = ExampleUtils.buildRegistry("examples.xml");

        // Since we know there's exactly *one* service-point implementing Calculator,
        // we can get it this way, and never have to know its service id.

        Calculator calculator = (Calculator) registry.getService(Calculator.class);

        System.out.println("Inputs:   " + arg0 + " and " + arg1);
        System.out.println("Add:      " + calculator.add(arg0, arg1));
        System.out.println("Subtract: " + calculator.subtract(arg0, arg1));
        System.out.println("Multiply: " + calculator.multiply(arg0, arg1));
        System.out.println("Divide:   " + calculator.divide(arg0, arg1));
       
        registry.shutdown();

嗯,Registry registry = ExampleUtils.buildRegistry("examples.xml");  這條語句看來是從examples.xml中進行相應的初始化並建立對應關係了,內部大概是根據配置文件定義攔截器,工廠,初始化方法之類,不用看。這裏的Registry應該等於Spring中的ApplicationContext, Pico中的Configuration了。看了IoC容器這方面的也沒什麼別的東西,一定得有一個全局的東西hold這些被管理的類的。

下面的registry.getService(Calculator.class);看起來要比Spring的appContext.getBean(beanId)方便一點,在整個配置文件保證藉口唯一的前提下,可以直接採用class作爲參數取出對象。當然Spring完全可以這麼做,只看Johnson先生高興不高興了。

Caculator接口繼承了增刪改查接口(就是4個各包含一個方法的接口)。

再看看examples.xml配置:

<module id="examples" version="1.0.0">
    <service-point id="Adder" interface="org.apache.hivemind.examples.Adder">
        <create-instance class="org.apache.hivemind.examples.impl.AdderImpl"/>
        <interceptor service-id="hivemind.LoggingInterceptor"/>
    </service-point>
    ...其他操作省略
    <service-point id="Calculator" interface="org.apache.hivemind.examples.Calculator">
        <invoke-factory>
            <!-- Most properties are autowired by the BuilderFactory -->
            <construct class="org.apache.hivemind.examples.impl.CalculatorImpl"/>
        </invoke-factory>
        <interceptor service-id="hivemind.LoggingInterceptor"/>
    </service-point>
</module>

仔細看看這個配置文件就可以看出一些有趣的東西:
service-point毫無疑問等於Spring中的bean。(Howard同志一向以長的配置名稱聞名,這一點可以在Tapestry的配置文件中得到證實,不過比起Spring的超長package name和constant name,似乎又差了一點,呵呵),id, interface……等等,看來hlship完全不鼓勵在這個Container中使用具體的類了,看看DTD文件的定義:

<service-point id=".." interface=".."
   [parameters-schema-id=".."]
   [parameters-occurs="unbounded |
             0..1 | 1 | 1..n | none"]>
 [parameters-schema]
 [create-instance]
 [invoke-factory]
 [interceptor]
</service-point>

確實沒有class這個屬性……這樣做好還是不好?……不知道,完全面向接口的系統存在嗎……這個問題暫時不想,以後再說。四個加減乘除的類的生成沒什麼好說的,看看
<service-point id="Adder" interface="org.apache.hivemind.examples.Adder">
     <create-instance class="org.apache.hivemind.examples.impl.AdderImpl"/>
     <interceptor service-id="hivemind.LoggingInterceptor"/>
</service-point>
的意思,應該是創建一個以org.apache.hivemind.examples.impl.AdderImpl的實例,從<create-instance>的DTD看來,他允許創建爲primitive, singleton, threaded, pooled的形式。默認應該是每次調用創建一個實例吧,我猜。然後用一個攔截器(LogginInterceptor)來處理。

這裏又發現了一個比Spring要方便的地方,interceptor可以直接定義在(我都不知道怎麼說了,用Bean還是service-point?)Component的內部,用Spring的話還得另外建立一個新的Bean,然後指定Advice的作用域,如果系統中只有一兩處需要的話,多一個Bean的配置顯得有點不雅。記得xWork也是這樣定義interceptor的。

下面的按照工廠形式創建實例有點意思。

    <service-point id="Calculator" interface="org.apache.hivemind.examples.Calculator">
        <invoke-factory>
            <!-- Most properties are autowired by the BuilderFactory -->
            <construct class="org.apache.hivemind.examples.impl.CalculatorImpl"/>
        </invoke-factory>
        <interceptor service-id="hivemind.LoggingInterceptor"/>
    </service-point>

先看看CaculatorImpl的實現:
public class CalculatorImpl implements Calculator {
    private Adder _adder;
    private Subtracter _subtracter;
    private Multiplier _multiplier;
    private Divider _divider;

    public double add(double arg0, double arg1) {
        return _adder.add(arg0, arg1);
    }

    ...後面的減乘除就不寫了,類似

    ...一堆的setter/getter就不寫了
}


剛開始詫異了一下,在我感覺裏,這裏怎麼說應該有個輸入參數的地方,就象下面:

   <invoke-factory>
        <construct class="org.apache.hivemind.examples.impl.CalculatorImpl">
 <set-property name="adder" ref="Adder" />
 ...
 </construct>
   </invoke-factory>

看看他的註釋:Most properties are autowired by the BuilderFactory,看樣子他在BuilderFactory中默認將同id的service-point注入到construct中去了,這種便利是否必要?畢竟遍歷一個類的set方法,判斷方法所需的類型,尋找registry中的service-point然後注入,這都是需要代價的……沒想清楚,暫時放下。

題外話:我沒有一直跟隨HiveMind的版本變化,但在我的記憶中,1.0的某個rc版本將配置文件換成了Howard同志自己發明的Simple Data Language,其實就是hlship根據JavaCC自己組織了一套語法,然後將所有的配置文件用這種語法改寫……沒多少日子這個東西就被pass掉了。直到現在我還懷疑他做這件事情的動機,目前最能讓我覺得有趣的一種解釋是:Howard看到JavaCC很強大,能夠很輕易的定義一種新的語法並解析,具備Tapestry全新的創意的Howard,一時頭腦發熱就加入了這個東東……呵呵

HiveMind還有一些其他的特性,比如系統所有配置的文檔生成(這個功能Spring加上就好了)以及其他的一些方便的特性。Howard一再強調HiveMind是一個Micro Kernel的框架,但在我看來,他是一個新的,可能更加方便的,完全面向接口的,基於IoC的容器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章