<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 4,comments - 30,trackbacks - 0
    在日本,Seasar2這個(gè)框架十分的流行。Seasar2其實(shí)就是類似于Spring的一個(gè)開源框架

    大家有興趣的話,可以去官方網(wǎng)站看看: http://www.seasar.org/index.html

    中文版現(xiàn)在還沒完善,大家可能要用日文或則英文來了解

    下面簡單介紹一下:

    所謂“Seasar2”就是一個(gè)“輕量級(jí)容器”,面向無法擺脫“Java 應(yīng)用開發(fā)”之煩惱的所謂“開發(fā)者”,它能夠保證開發(fā)的“高生產(chǎn)率和高品質(zhì)”。并且同“其它輕量級(jí)容器”不同的是,“完全不需要書寫設(shè)定文件”,“就算是應(yīng)用程序發(fā)生改動(dòng)也無需再次起動(dòng)即可直接識(shí)別變更,因此具有腳本語言的靈活性”。

    為了不用寫設(shè)定文件也能夠運(yùn)行,Convention over Configuration的思想得以采用。Convention over Configuration就是指,“只要遵守一個(gè)適當(dāng)?shù)囊?guī)約,即使不用進(jìn)行非常麻煩的設(shè)定,框架結(jié)構(gòu)也可以自動(dòng)替我們搞定的思想”,這一思想是Ruby on Rails中所倡導(dǎo)的。Seasar2的Convention over Configuration是從Ruby on Rails 那里得到的提示而產(chǎn)生的。

    使用Seasar2的話,對(duì)于僅僅需要維護(hù)數(shù)據(jù)表這樣簡單的應(yīng)用,可以在不到3分鐘的時(shí)間里作成。

    應(yīng)用程序發(fā)生改動(dòng)之時(shí)也無需啟動(dòng)便可立即識(shí)別變更的機(jī)能在Seasar2里被稱為HOT deploy



    安裝:

    S2需要安裝JDK1.4 or JDK1.5。

    將S2xxx.zip解壓之后的seasar2目錄引入到Eclipse、「文件→導(dǎo)入→既存的工程」。

    使用Seasar2基本功能(S2Container, S2AOP)的時(shí)候、CLASSPATH的下面必須包含以下文件。

    • lib/aopalliance-1.0.jar
    • lib/commons-logging-1.1.jar
    • lib/javassist-3.4.ga.jar
    • lib/ognl-2.6.9-patch-20070624.jar
    • lib/s2-framework-2.x.x.jar
    • lib/geronimo-j2ee_1.4_spec-1.0.jar (參考下面)
    • lib/portlet-api-1.0.jar (任選項(xiàng))
    • lib/log4j-1.2.13.jar (任選項(xiàng))
    • resources/log4j.properties (任選項(xiàng))
    • resources/aop.dicon (任選項(xiàng))

    使用Seasar2的擴(kuò)張機(jī)能(S2JTA, S2DBCP, S2JDBC, S2Unit, S2Tx, S2DataSet)的時(shí)候必須要將以下文件追加到CLASSPATH里面。

    • lib/junit-3.8.2.jar
    • lib/poi-2.5-final-20040804.jar
    • lib/s2-extension-2.x.x.jar
    • lib/geronimo-jta_1.1_spec-1.0.jar (參考下面)
    • lib/geronimo-ejb_2.1_spec-1.0.jar (參考下面)
    • resources/jdbc.dicon

    根據(jù)應(yīng)用軟件所需的執(zhí)行環(huán)境、選擇以下需要引用的文件[geronimo-j2ee_1.4_spec-1.0.jar、geronimo-jta_1.0.1B_spec-1.0.jar、geronimo-ejb_2.1_spec-1.0.jar]

    環(huán)境geronimo-j2ee_1.4_spec-1.0.jargeronimo-jta_1.1_spec-1.0.jargeronimo-ejb_2.1_spec-1.0.jar
    不完全對(duì)應(yīng)J2EE的Servlet container
    (Tomcat等)
    不要
    (使用S2JTA,S2Tx的時(shí)候)

    (使用S2Tiger的時(shí)候)
    完全對(duì)應(yīng)J2EE的應(yīng)用服務(wù)器
    (JBoss, WebSphere, WebLogic等)
    不要不要不要
    獨(dú)立
    (使用S2JTA,S2Tx時(shí)候)
    不要不要

    為了讓大家更簡單的體驗(yàn)數(shù)據(jù)庫機(jī)能、使用了HSQLDB作為RDBMS。為了能夠體驗(yàn)Oracle機(jī)能、準(zhǔn)備了hsql/sql/demo-oracle.sql。SQL*Plus等執(zhí)行了之后、請(qǐng)根據(jù)環(huán)境的需要改寫jdbc.dicon的XADataSourceImpl的設(shè)定項(xiàng)目

    請(qǐng)使用S2Container用的插件Kijimuna

    想使用EJB3anoteshon的情況下、將 S2TigerXXX.zip解壓縮后的s2-tiger目錄引入Eclipse、「文件→導(dǎo)入→既存的工程」。 在Seasar2的設(shè)定基礎(chǔ)上、必需要將以下的文件追加到CLASSPATH里面。

    • lib/s2-tiger-x.x.x.jar
    • resources/jdbc.dicon

    想使用Tigeranoteshon的情況、將S2TigerXXX.zip解凍后的s2-tiger目錄引入Eclipse、「文件→進(jìn)口→既存的項(xiàng)目」。 在Seasar2的設(shè)定基礎(chǔ)上、必需要將以下的文件追加到CLASSPATH里面。

    • lib/s2-tiger-x.x.x.jar

    ?

    快速上手

    S2Container,就是進(jìn)行Dependency Injection(注:依賴注入——譯者)(以后略稱為DI)的一個(gè)輕量級(jí)容器。DI,就是Interface和實(shí)裝分離,程序相互之間僅通過Interface來會(huì)話的一種思考方式。

    最初的一步

    讓我們趕快試一試吧。登場人物如下。

    • 問候語類
      • 返回問候語的字符串。
    • 問候客戶端類
      • 從問候類獲得問候語(字符串)并輸出到終端屏幕。
    • 問候語應(yīng)用主類
      • 啟動(dòng)用的類。用來組織問候語類和問候語使用者類的組成方式。
    Greeting.java

    問侯語的Interface。

    package examples.di;
    
    public interface Greeting {
    
        String greet();
    }
    
    GreetingImpl.java

    問候語的實(shí)裝。

    package examples.di.impl;
    
    import examples.di.Greeting;
    
    public class GreetingImpl implements Greeting {
    
        public String greet() {
            return "Hello World!";
        }
    }
    
    GreetingClient.java

    使用問候語的使用者客戶端Interface。

    package examples.di;
    
    public interface GreetingClient {
    
        void execute();
    }
    
    GreetingClientImpl.java

    使用問候語的客戶端的實(shí)裝。不是直接使用這個(gè)GreetngImpl(實(shí)裝),而是通過Greeting(Interface)來實(shí)現(xiàn)問候的機(jī)能。

    package examples.di.impl;
    
    import examples.di.Greeting;
    import examples.di.GreetingClient;
    
    public class GreetingClientImpl implements GreetingClient {
    
        private Greeting greeting;
    
        public void setGreeting(Greeting greeting) {
            this.greeting = greeting;
        }
    
        public void execute() {
            System.out.println(greeting.greet());
        }
    }
    

    機(jī)能提供端和使用端的準(zhǔn)備都完成了。下面我們就執(zhí)行一下試試吧。

    GreetingMain.java
    package examples.di.main;
    
    import examples.di.Greeting;
    import examples.di.impl.GreetingClientImpl;
    import examples.di.impl.GreetingImpl;
    
    public class GreetingMain {
    
        public static void main(String[] args) {
            Greeting greeting = new GreetingImpl();
            GreetingClientImpl greetingClient = new GreetingClientImpl();
            greetingClient.setGreeting(greeting);
            greetingClient.execute();
        }
    }
    

    實(shí)行結(jié)果如下。

    Hello World!
    

    象這樣機(jī)能的使用者(GreetingClientImpl)經(jīng)由Interface(Greeting)的中介來使用機(jī)能,具體的機(jī)能對(duì)象(既Interface的實(shí)裝類)在實(shí)行的時(shí)候由第三者(在這里是GreetingMain)來提供的情況,就是DI的基本思考方法。

    但是,如果象GreetingMain中那樣實(shí)裝類的設(shè)定內(nèi)容直接被寫出來的話,一旦實(shí)裝類需要變更的時(shí)候源代碼也必須跟著修正。為了避免這個(gè)麻煩,DIContainer就登場了。把實(shí)裝設(shè)定抽出到一個(gè)設(shè)定文件中,由DIContainer把這個(gè)設(shè)定文件讀入并組織對(duì)象運(yùn)行。

    那么,讓我們?cè)囍褎偛诺奶岬降哪莻€(gè)設(shè)定文件的內(nèi)容寫一下。S2Container中,設(shè)定文件的后綴是".dicon"。

    GreetingMain2.dicon
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC
    "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components>
    <component name="greeting"
    class="examples.di.impl.GreetingImpl"/>
    <component name="greetingClient"
    class="examples.di.impl.GreetingClientImpl">
    <property name="greeting">greeting</property>
    </component>
    </components>

    ?

    <component name="greeting"
    class="examples.di.impl.GreetingImpl"/>

    上文記載的是組件的定義。在這里,相當(dāng)于如下的Java代碼。

    Greeting greeting = new GreetingImpl();
    

    component標(biāo)簽的name屬性指定了組件的名稱,class屬性指定了組件的Java類文件名。下文就是greetingClient的設(shè)定。

    <component name="greetingClient"
    class="examples.di.impl.GreetingClientImpl">
    <property name="greeting">greeting</property>
    </component>

    property標(biāo)簽的name屬性指定了組件Java類中的屬性名,標(biāo)簽的定義體則指定了一個(gè)組件名稱。這個(gè)設(shè)定相當(dāng)于如下Java代碼。組件名要注意不要用["]括起來。用["]括起來的話就會(huì)被當(dāng)作字符串來處理了。

    GreetingClientImpl greetingClient = new GreetingClientImpl();
    greetingClient.setGreeting(greeting);
    

    利用S2Container的起動(dòng)類的內(nèi)容如下。

    GreetingMain2.java
    package examples.di.main;
    
    import org.seasar.framework.container.S2Container;
    import org.seasar.framework.container.factory.S2ContainerFactory;
    
    import examples.di.GreetingClient;
    
    public class GreetingMain2 {
    
        private static final String PATH =
            "examples/di/dicon/GreetingMain2.dicon";
    
        public static void main(String[] args) {
            S2Container container =
                S2ContainerFactory.create(PATH);
            container.init();
            GreetingClient greetingClient = (GreetingClient)
                container.getComponent("greetingClient");
            greetingClient.execute();
        }
    }
    

    S2Container,是由S2ContainerFactory#create(String path)做成的。更加詳細(xì)的內(nèi)容請(qǐng)參照S2Container的生成

    組件(greetingClient),是由S2Container#getComponent(String componentName)的方法取得的。詳細(xì)內(nèi)容請(qǐng)參照組件的取得

    實(shí)行結(jié)果同先前一樣表示如下。

    Hello World!
    

    經(jīng)常同DI一起使用的是AOP。AOP是指、將日志等的輸出分散到復(fù)數(shù)個(gè)類中的邏輯模塊化的一種技術(shù)。那么、讓我們不修改已經(jīng)作成的GreetingImpl、GreetingClinetImpl的源代碼?試著將日志(追蹤)輸出。 適用于AOP的設(shè)定文件如下。

    GreetingMain3.dicon
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC
    "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components>
    <include path="aop.dicon"/>
    <component name="greeting"
    class="examples.di.impl.GreetingImpl">
    <aspect>aop.traceInterceptor</aspect>
    </component>
    <component name="greetingClient"
    class="examples.di.impl.GreetingClientImpl">
    <property name="greeting">greeting</property>
    <aspect>aop.traceInterceptor</aspect>
    </component>
    </components>

    Seasar2中,經(jīng)常使用的AOP模塊在aop.dicon中預(yù)先定義。 象下面這樣、使用include標(biāo)簽。 更加詳細(xì)的?敬請(qǐng)參照S2Container定義的分解和引入

    <include path="aop.dicon"/>
    

    對(duì)于在組件中適用的AOP來說?我們component標(biāo)簽的字標(biāo)簽 aspect標(biāo)簽的正文中指定AOP的模塊名稱。aop.traceInterceptor是AOP模塊的名字。

    <aspect>aop.traceInterceptor</aspect>
    

    AOP的設(shè)定如上所述。那么就讓我們執(zhí)行一下GreetingMain3吧。同GreetingMain2不同的僅僅是設(shè)定文件的路徑而已。

    GreetingMain3.java
    package examples.di.main;
    
    import org.seasar.framework.container.S2Container;
    import org.seasar.framework.container.factory.S2ContainerFactory;
    
    import examples.di.GreetingClient;
    
    public class GreetingMain3 {
    
        private static final String PATH =
            "examples/di/dicon/GreetingMain3.dicon";
    
        public static void main(String[] args) {
            S2Container container =
                S2ContainerFactory.create(PATH);
            GreetingClient greetingClient = (GreetingClient)
                container.getComponent("greetingClient");
            greetingClient.execute();
        }
    }
    

    執(zhí)行結(jié)果如下。可以明白一點(diǎn),沒有修改源代碼,日志就被輸出了。

    DEBUG 2005-10-11 21:01:49,655 [main] BEGIN examples.di.impl.GreetingClientImpl#execute()
    DEBUG 2005-10-11 21:01:49,665 [main] BEGIN examples.di.impl.GreetingImpl#greet()
    DEBUG 2005-10-11 21:01:49,665 [main] END examples.di.impl.GreetingImpl#greet() : Hello World!
    Hello World!
    DEBUG 2005-10-11 21:01:49,675 [main] END examples.di.impl.GreetingClientImpl#execute() : null
    

    這樣、S2Container的基本使用方法就被掌握了。

    更進(jìn)一步

    但是,不管怎么說書寫設(shè)定文件都是一件麻煩的事啊。在S2Container中,為了盡可能的減少設(shè)定文件的記述量、采用了如下的概念。

    就是說制定一個(gè)適當(dāng)?shù)囊?guī)約,遵守這個(gè)規(guī)約的話?無需什么設(shè)定也可以運(yùn)作。比如說,剛才的設(shè)定文件中,象下面這樣明確地指定屬性的部分存在著。

    <component name="greetingClient"
    class="examples.di.impl.GreetingClientImpl">
    <property name="greeting">greeting</property>
    </component>

    S2Container中、屬性的類型是Interface的情形下? 如果要將屬性類型的實(shí)裝組件注冊(cè)進(jìn)軟件容器中, 不需要什么特殊的設(shè)定也可以自動(dòng)得運(yùn)作DI的機(jī)能。 這就是,如果遵守DI中推薦的所謂“屬性類型用Interface定義”的規(guī)則,S2Container會(huì)自動(dòng)地處理一切。

    雖然一說到規(guī)約就容易產(chǎn)生麻煩之類的想法,“推薦而已,如果遵守的話就能使開發(fā)愉快”的話,遵守規(guī)約的動(dòng)機(jī)就產(chǎn)生了。這才是問題的重點(diǎn)。

    如上的設(shè)定,可以做如下化簡

    <component name="greetingClient"
    class="examples.di.impl.GreetingClientImpl">
    </component>

    實(shí)際上?剛才的AOP的例子也適用“Convention over Configuration”。 通常在AOP中,AOP的模塊在什么地方適用是由pointcut指定的,S2AOP的情況下? 如果遵守所謂“使用Interface”這個(gè)推薦的規(guī)約,不指定pointcut,自動(dòng)的適用于在Interface中定義的所有方法。因?yàn)橛羞@個(gè)機(jī)能,在剛才的那個(gè)例子中,就沒有必要指定pointcut。

    雖然根據(jù)“Convention over Configuration”,DI和AOP的設(shè)定可以得以簡化,需要處理的組件數(shù)增加了、僅僅組件的注冊(cè)也會(huì)變成一個(gè)非常累的作業(yè)。那么這個(gè)組件注冊(cè)自動(dòng)化就叫做組件自動(dòng)注冊(cè)機(jī)能。 剛才的GreetingImpl、GreetingClientImpl的注冊(cè)自動(dòng)化如下。

    <component
    class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
    <arg>"examples.di.impl"</arg>
    <arg>".*Impl"</arg>
    </initMethod>
    </component>

    FileSystemComponentAutoRegister組件將addClassPattern方法指定的類從文件系統(tǒng)中探尋出來,自動(dòng)注冊(cè)到S2Container中。關(guān)于initMethod標(biāo)簽,請(qǐng)參照方法函數(shù)注入

    addClassPattern方法的第一個(gè)參數(shù)是想要注冊(cè)的組件的包的名字。 子包的內(nèi)容也會(huì)用回歸的方式檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”做分隔符指定復(fù)數(shù)個(gè)設(shè)定。

    根據(jù)組件自動(dòng)注冊(cè)原則,即使后續(xù)追加組件的情況下,也沒有必要追加設(shè)定,這樣手續(xù)就大大地簡化了。

    如果組件的自動(dòng)化注冊(cè)可以了,接下來就會(huì)想讓AOP的注冊(cè)也自動(dòng)化了吧。剛才的GreetingImpl、GreetingClientImp的AOP注冊(cè)自動(dòng)化的設(shè)定如下。

    <include path="aop.dicon"/>
    ...
    <component
    class="org.seasar.framework.container.autoregister.AspectAutoRegister">
    <property name="interceptor">aop.traceInterceptor</property>
    <initMethod name="addClassPattern">
    <arg>"examples.di.impl"</arg>
    <arg>".*Impl"</arg>
    </initMethod>
    </component>

    用interceptor屬性指定AOP的名稱。addClassPattern方法同組件的自動(dòng)化注冊(cè)時(shí)的用法一樣,這里就不做特殊的說明了。 組件自動(dòng)化注冊(cè)和AOP自動(dòng)化注冊(cè)的例子如下。

    GreetingMain4.dicon
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd"> <components>
    <include path="aop.dicon"/> <component
    class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
    <arg>"examples.di.impl"</arg>
    <arg>".*Impl"</arg>
    </initMethod>
    </component> <component
    class="org.seasar.framework.container.autoregister.AspectAutoRegister">
    <property name="interceptor">aop.traceInterceptor</property>
    <initMethod name="addClassPattern">
    <arg>"examples.di.impl"</arg>
    <arg>".*Impl"</arg>
    </initMethod>
    </component>
    </components>

    那么來執(zhí)行一下GreetingMain4吧。 自動(dòng)注冊(cè)的情況下,S2Container#init()和S2Container#destroy()的調(diào)用是必要的。

    GreetingMain4.java
    package examples.di.main;
    
    import org.seasar.framework.container.S2Container;
    import org.seasar.framework.container.factory.S2ContainerFactory;
    
    import examples.di.GreetingClient;
    
    public class GreetingMain4 {
    
        private static final String PATH =
            "examples/di/dicon/GreetingMain4.dicon";
    
        public static void main(String[] args) {
            S2Container container =
                S2ContainerFactory.create(PATH);
            container.init();
            try {
                GreetingClient greetingClient = (GreetingClient)
                    container.getComponent("greetingClient");
                greetingClient.execute();
            } finally {
                container.destroy();
            }
        }
    }
    

    執(zhí)行的結(jié)果同GreetingMain3一樣如下列出。

    DEBUG 2005-10-12 16:00:08,093 [main] BEGIN examples.di.impl.GreetingClientImpl#execute()
    DEBUG 2005-10-12 16:00:08,103 [main] BEGIN examples.di.impl.GreetingImpl#greet()
    DEBUG 2005-10-12 16:00:08,103 [main] END examples.di.impl.GreetingImpl#greet() : Hello World!
    Hello World!
    DEBUG 2005-10-12 16:00:08,103 [main] END examples.di.impl.GreetingClientImpl#execute() : null
    

    大多數(shù)的情況下?自動(dòng)注冊(cè)和自動(dòng)綁定的組合方式都能順利的進(jìn)行下去。不想要自動(dòng)注冊(cè)的組件存在的情況下,自動(dòng)注冊(cè)組件中準(zhǔn)備了addIgnoreClassPattern方法,可以指定自動(dòng)注冊(cè)外的組件。

    不想要自動(dòng)綁定的屬性存在的情況下,使用Binding備注碼,不使用設(shè)定文件也可以做細(xì)節(jié)的調(diào)整。

    使用Hotswap的話?應(yīng)用程序在運(yùn)行中重新書寫更換類文件,馬上就能夠直接測試結(jié)果。不需要一個(gè)一個(gè)地將應(yīng)用程序在啟動(dòng),因此開發(fā)的效率能夠得到大幅度的提高。

    現(xiàn)在,關(guān)于S2Container的高級(jí)使用方法也可以掌握了。這之后嘛,只要根據(jù)需要參照對(duì)應(yīng)的操作手冊(cè)就可以了。

    S2Container參考

    需要作成的文件

    為了使用S2Container,定義文件的做成是必要的。定義文件就像是為了組織組件而制作的設(shè)計(jì)書一樣的東西。形式為XML,后綴為dicon。

    S2Container的定義

    S2Container的定義、象下面這樣。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components>
        <component name="..." class="...">
                ...
        </component>
        <component name="..." class="...">
                ...
        </component>
    </components>
    

    DOCTYPE是不能省略的。dicon做成的時(shí)候、請(qǐng)將前述例子拷貝粘貼。根是components標(biāo)簽。每一個(gè)組件用component標(biāo)簽定義。用component標(biāo)簽的class屬性指定組件的類的全名。在name屬性中、指定組件的名稱。詳細(xì)內(nèi)容請(qǐng)參照S2Container定義標(biāo)簽參考

    <components>
        <component name="hoge" class="examples.dicon.HogeImpl"/>
    </components>
    

    S2Container的生成

    S2Container的生成方法有兩種。

    • 使用SingletonS2ContainerFactory。
    • 使用S2ContainerFactory。

    使用SingletonS2ContainerFactory

    使用SingletonS2ContainerFactory的情況下,使用如下方法。

    - org.seasar.framework.container.factory.SingletonS2ContainerFactory#init()

    定義文件使用的是CLASSPATH所指定的路徑中存在的app.dicon。

    做成的S2Container,無論在什么地方都是可以從如下方法中取得。

    - org.seasar.framework.container.factory.SingletonS2ContainerFactory#getContainer()

    SingletonS2ContainerFactory.init();
    ...
    S2Container container = SingletonS2ContainerFactory.getContainer();
    

    定義文件的路徑需要被指定的情況下應(yīng)在調(diào)用init()之前執(zhí)行如下方法。

    - org.seasar.framework.container.factory.SingletonS2ContainerFactory#setConfigPath(String Path)

    參數(shù)path是相對(duì)于以CLASSPATH指定的路徑為根的定義文件的絕對(duì)路徑。例如,WEB-INF/classes/aaa.dicon 的情況下就是aaa.dicon,WEB-INF/classes/aaa/bbb/ccc.dicon的情況下就是aaa/bbb/ccc.dicon。分隔符在Windows和Unix下都是/。

    private static final String PATH = "aaa/bbb/ccc.dicon";
    ...
    SingletonS2ContainerFactory.setConfigPath(PATH);
    SingletonS2ContainerFactory.init();
    ...
    S2Container container = SingletonS2ContainerFactory.getContainer();
    

    使用S2ContainerFactory

    使用S2ContainerFactory的場合下,使用如下方法。

    - org.seasar.framework.container.factory.S2ContainerFactory#create(String path)

    S2Container生成之后需要許呼叫下一個(gè)方法。

    - org.seasar.framework.container.S2Container#init()

    private static final String PATH = "aaa/bbb/ccc.dicon";
    ...
    S2Container container = S2ContainerFactory.create(PATH);
    container.init();
    

    用這個(gè)方法取得的組件的實(shí)例,有必要進(jìn)行在應(yīng)用中的管理。

    組件的取得

    從S2Container中將組件取出來,使用下面的方法。

    - org.seasar.framework.container.S2Container#getComponent(Object componentKey)

    參數(shù)中指定的是組件的類或者是組件的名稱。詳細(xì)的請(qǐng)參照component標(biāo)簽。要指定組件的類,只要是 組件 instanceof 類 的操作返回為true的類就能夠指定。但是、S2Container中所指定的類對(duì)應(yīng)了好幾個(gè)實(shí)裝的組件的時(shí)候,S2Container將不能判斷返回哪一個(gè)組件為好,這樣就會(huì)發(fā)生TooManyRegistrationRuntimeException。請(qǐng)指定實(shí)裝組件為唯一的類。也可以用組件名稱取得組件。這種情況下也是同樣,用一個(gè)名稱的復(fù)數(shù)個(gè)組件被注冊(cè)的情況下,將發(fā)生TooManyRegistrationRuntimeException。指定組件名的場合下,因?yàn)橐部赡馨l(fā)生拼寫錯(cuò)誤,所以盡可能的指定組件的類為好。

    例)通過指定類來取得組件的場合

    S2Container container = S2ContainerFactory.create(PATH);
    Hoge hoge = (Hoge) container.getComponent(Hoge.class);
    

    例)通過指定組件名來取得組件場合

    S2Container container = S2ContainerFactory.create(PATH);
    Hoge hoge = (Hoge) container.getComponent("hoge");
    

    Dependency Injection的類型

    在Dependency Injection中,組件的構(gòu)成所必要的值是用構(gòu)造函數(shù)來設(shè)定(Constructor Injection),還是用設(shè)定函數(shù)來設(shè)定(Setter Injection),或者是用初始化函數(shù)來設(shè)定(Method Injection),這樣進(jìn)行分類。Method Injection是S2Container的本源。S2Container支持以上所有類型和混合類型。

    構(gòu)造函數(shù)?注入

    對(duì)構(gòu)造函數(shù)的參數(shù)進(jìn)行DI,這就是構(gòu)造函數(shù)注入。
    S2Container的定義文件中,記述如下內(nèi)容。

    • 組件的指定
      組件,用component標(biāo)簽來組建。用class指定對(duì)應(yīng)的類。
      也可以用name屬性給組件起名稱。
    • 構(gòu)造函數(shù)的參數(shù)的指定
      組件的構(gòu)造函數(shù)的參數(shù)用component標(biāo)簽的子標(biāo)簽arg標(biāo)簽來指定。
      值為字符串的時(shí)候,用雙引號(hào)(")括起來。
    <components>
        <component name="..." class="...">
              <arg>...</arg>
        </component>
    </components>
    

    設(shè)定函數(shù)?注入

    設(shè)定函數(shù)注入是指對(duì)于任意一個(gè)屬性變量使用設(shè)定函數(shù)來行使DI。
    S2Container的定義文件中作如下內(nèi)容的記述。

    • 組件的指定
      組件的指定同構(gòu)造函數(shù)注入相同。
    • 屬性變量的指定
      組件的屬性變量用component標(biāo)簽的子標(biāo)簽property來指定。
      用name屬性來指定變量的名稱。
    <components>
        <component name="..." class="...">
              <property name="...">...</property>
        </component>
    </components>
    

    方法函數(shù)?注入

    方法函數(shù)注入是指,通過任意一個(gè)函數(shù)的調(diào)用來完成DI的功能。
    S2Container的定義文件中,記述如下內(nèi)容。

    • 組件的指定
      組件的指定同構(gòu)造函數(shù)注入相同。
    • 初始化方法函數(shù)的指定
      使用initMethod標(biāo)簽,調(diào)用組件的任意一個(gè)方法函數(shù)。在name屬性中,指定方法函數(shù)的名稱。 用arg標(biāo)簽指定參數(shù),name屬性省略,在正文中,使用OGNL式也可以。
    <components>
        <component name="..." class="...">
            <initMethod name="...">
                <arg>...</arg>
            </initMethod>
        </component>
    </components>
    

    S2Container定義的分割和引入

    所有的組件用一個(gè)文件來設(shè)定的話,很快就會(huì)變得臃腫而難以管理。因此,S2Container就具有了將組件的定義進(jìn)行復(fù)數(shù)個(gè)分割的機(jī)能和將多個(gè)分割的定義文件引入而組織成一個(gè)文件的機(jī)能。S2Container定義文件的引入方法如下。

    <components>
        <include path="bar.dicon"/>
    </components>
    

    include標(biāo)簽的path屬性被用來指定想要引入的S2Container定義文件的路徑。詳細(xì)情況請(qǐng)參照include標(biāo)簽
    組件的檢索順序,先是在自身注冊(cè)的文件中尋找組件,沒有找到所需組件的情況下,將按照include的順序在子定義文件中查找注冊(cè)到S2Container中的組件,最先找到的那個(gè)組件將被返回。

    <components>
        <include path="aaa.dicon"/>
        <include path="bbb.dicon"/>
        <component class="example.container.Foo" />
    </components>
    

    命名空間

    組件的定義被分割的情況下,為了不讓復(fù)數(shù)個(gè)組件的定義名稱發(fā)生沖突,可以用components標(biāo)簽的namespace屬性指定命名空間。

    foo.dicon
    <components namespace="foo">
        <component name="aaa" .../>
        <component name="bbb" ...>
            <arg>aaa</arg>
        </component>
    </components>
    
    bar.dicon
    <components namespace="bar">
        <include path="foo.dicon"/>
        <component name="aaa" .../>
        <component name="bbb" ...>
            <arg>aaa</arg>
        </component>
        <component name="ccc" ...>
            <arg>foo.aaa</arg>
        </component>
    </components>
    
    app.dicon
    <components>
        <include path="bar.dicon"/>
    </components>
    

    在同一個(gè)組件定義文件中可以不需要指定命名空間而調(diào)用組件。調(diào)用其它S2Container文件中定義的組件時(shí),要在組件名前加上命名空間。foo.aaa 和 bar.aaa 雖然有相同名稱的組件,但是因?yàn)槊臻g的不同,就被認(rèn)為是不同的組件。

    實(shí)例(instance)管理

    在S2Container中,怎么樣對(duì)實(shí)例進(jìn)行管理,這個(gè)設(shè)定是用component標(biāo)簽的instance屬性。

    instance屬性說明
    singleton(default)不論S2Container.getComponent()被調(diào)用多少次都返回同一個(gè)實(shí)例。
    prototypeS2Container.getComponent()每次被調(diào)用的時(shí)候都返回一個(gè)新的實(shí)例。
    request對(duì)應(yīng)每一個(gè)請(qǐng)求(request)做成一個(gè)實(shí)例。用name屬性中指定的名稱,組件被容納在請(qǐng)求中。使用request的場合下需要設(shè)定S2ContainerFilter
    session對(duì)應(yīng)每一個(gè)session做成一個(gè)實(shí)例。用name屬性中指定的名稱,組件被容納在session中。使用session的場合下需要設(shè)定S2ContainerFilter
    application使用Servlet的場合下,對(duì)應(yīng)每一個(gè)ServletContext做成一個(gè)實(shí)例。用name屬性中指定的名稱,組件被容納在ServletContext中。使用application的場合下需要設(shè)定S2ContainerFilter
    outer組件的實(shí)例在S2Container之外作成,從而僅僅行使Dependency Injection的功能。Aspect構(gòu)造函數(shù)注入不能適用。

    生存周期

    使用initMethod 和 destroyMethod組件的生存周期也可以用容器來管理。在S2Container的開始時(shí)用(S2Container.init())調(diào)用initMethod標(biāo)簽中指定的方法,S2Container結(jié)束時(shí)用(S2Container.destroy())調(diào)用destroyMethod標(biāo)簽中指定的方法。initMethod將按照容器中注冊(cè)的組件的順序來執(zhí)行組件,destroyMethod則按照相反的順序去執(zhí)行。instance屬性是singleton之外的情況下,指定了destroyMethod也會(huì)被忽視。java.util.HashMap#put()方法中初始化(給aaa賦值為111)?結(jié)束處理(給aaa賦值為null)的設(shè)定,向下面那樣。

    <components namespace="bar">
        <component name="map" class="java.util.HashMap">
            <initMethod name="put">
                <arg>"aaa"</arg>
                <arg>111</arg>
            </initMethod>
            <destroyMethod name="put">
                <arg>"aaa"</arg>
                <arg>null</arg>
            </destroyMethod>
        </component>
    </components>
    

    自動(dòng)綁定

    組件間的依存關(guān)系,類型是interface的場合時(shí),將由容器來自動(dòng)解決。這是在S2Container被默認(rèn)的,指定component標(biāo)簽的autoBinding屬性可以進(jìn)行更加細(xì)致的控制。

    autoBinding說明
    auto(default)適用于構(gòu)造函數(shù)和屬性變量的自動(dòng)綁定。
    constructor適用于構(gòu)造函數(shù)的自動(dòng)綁定。
    property適用于屬性變量的自動(dòng)綁定。
    none只能對(duì)構(gòu)造函數(shù)、屬性變量進(jìn)行手動(dòng)綁定。

    構(gòu)造函數(shù)的自動(dòng)綁定規(guī)則如下所示。

    • 明確指定了構(gòu)造函數(shù)的參數(shù)的情況下,自動(dòng)綁定將不再適用。
    • 不屬于上述情況,如果是定義了沒有參數(shù)的默認(rèn)的構(gòu)造函數(shù)的話,對(duì)于這個(gè)構(gòu)造函數(shù),自動(dòng)綁定也不適用。
    • 不屬于上述情況,參數(shù)的類型全是interface并且參數(shù)數(shù)目最多的構(gòu)造函數(shù)將被使用。 這樣,對(duì)于從容器中取得參數(shù)類型的實(shí)裝組件,自動(dòng)綁定是適用的。
    • 如果不是以上情況,自動(dòng)綁定將不適用。

    屬性變量的自動(dòng)綁定規(guī)則如下。

    • 明確指定了屬性變量的情況下,自動(dòng)綁定將不適用。
    • 不屬于上述情況,如果在容器的注冊(cè)組件中存在著可以代入屬性變量中的同名組件,自動(dòng)綁定將適用于該組件。
    • 不屬于上述情況,屬性變量的類型是interface并且該屬性類型的實(shí)裝組件在容器中注冊(cè)了的話,自動(dòng)綁定是適用的。
    • 如果不是以上情況,自動(dòng)綁定將不適用。

    用property標(biāo)簽的bindingType屬性,可以更加細(xì)致的控制屬性變量。

    bindingType說明
    must自動(dòng)綁定不適用的情況下?將會(huì)發(fā)生例外。
    should(default)自動(dòng)綁定不適用的情況下,將發(fā)出警告通知。
    may自動(dòng)綁定不適用的情況下,什么都不發(fā)生。
    noneautoBinding的屬性雖然是auto、property情況下,自動(dòng)綁定也不適用。

    在組件中利用S2Container

    不想讓組件依存于S2Container的情況下,根據(jù)組件的具體情況,在組件中需要調(diào)用S2Container的方法,這樣的場合也許會(huì)存在。S2Container自身也以container的名稱,自我注冊(cè)了。所以可以在arg,property標(biāo)簽的正文中指定container,從而取得容器的實(shí)例。還有,S2Container類型的setter方法定義好了后也可以做自動(dòng)綁定的設(shè)定。用arg,property標(biāo)簽指定container的情況下,向下面這樣進(jìn)行。

    <components>
        <component class="examples.dicon.BarImpl">
            <arg>container</arg>
        </component>
    
        <component class="examples.dicon.FooImpl">
            <property name="foo">container</property>
        </component>
    </components>
    

    S2ContainerServlet

    到此為止,在Java application中,是用明確表示的方法做成S2Container的,Web application的情況下,由誰來作成S2Container呢?為了達(dá)到這個(gè)目的,準(zhǔn)備了以下的類。

    • org.seasar.framework.container.servlet#S2ContainerServlet

    為了使用S2ContainerServlet,在web.xml中記述如下項(xiàng)目。

    <servlet>
        <servlet-name>s2servlet</servlet-name>
        <servlet-class>org.seasar.framework.container.servlet.S2ContainerServlet</servlet-class>
        <init-param>
            <param-name>configPath</param-name>
            <param-value>app.dicon</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>s2servlet</servlet-name>
        <url-pattern>/s2servlet</url-pattern>
    </servlet-mapping>
    

    用configPath來指定作為根的S2Container的定義路徑。定義文件將放在WEB-INF/classes中。對(duì)于S2ContainerServlet,為了比其它的servlet更早的起動(dòng),請(qǐng)做load-on-startup標(biāo)簽的調(diào)整。S2ContainerServlet起動(dòng)之后,可以用如下的方法函數(shù)取得S2Container的實(shí)例。

    • org.seasar.framework.container.factory.SingletonS2ContainerFactory#getContainer()

    另外,S2Container的生命周期和S2ContainerServlet是連動(dòng)的。debug變量被設(shè)為true的話,按照以下的方法,可以將運(yùn)行中的S2Container再次起動(dòng)。xxx是Web application的context名。

    http://localhost:8080/xxx/s2servlet?command=restart
                
    

    在使用了S2ContainerServlet的情況下,ServletContext將會(huì)作為一個(gè)組件可以用servletContext的名字來訪問。

    app.dicon的角色

    根的S2Container的定義文件,按照慣例用app.dicon的名稱。通常放在WEB-INF/classes中就好了。

    AOP的適用

    在組件中AOP的適用情況也可以被設(shè)定。比如,想要在ArrayList中設(shè)定TraceInterceptor使用的情況下需要象下面這樣做。

    <components>
        <component name="traceInterceptor"
                   class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
        <component class="java.util.ArrayList">
            <aspect>traceInterceptor</aspect>
        </component>
        <component class="java.util.Date">
            <arg>0</arg>
            <aspect pointcut="getTime, hashCode">traceInterceptor</aspect>
        </component>
    </components>
    

    aspect標(biāo)簽的正文中指定Interceptor的名字。pointcut的屬性中可以用逗號(hào)做分隔符指定AOP對(duì)象的方法的名字。pointcut的屬性沒有被指定的情況下,組件將把實(shí)裝的interface的所有方法函數(shù)作為AOP的對(duì)象。方法函數(shù)的名稱指定也可以用正則表達(dá)式(JDK1.4のregex)。這樣的定義例子如下。

    private static final String PATH =
        "examples/dicon/Aop.dicon";
    S2Container container = S2ContainerFactory.create(PATH);
    List list = (List) container.getComponent(List.class);
    list.size();
    Date date = (Date) container.getComponent(Date.class);
    date.getTime();
    date.hashCode();
    date.toString();
    

    執(zhí)行結(jié)果。

    BEGIN java.util.ArrayList#size()
    END java.util.ArrayList#size() : 0
    BEGIN java.util.Date#getTime()
    END java.util.Date#getTime() : 0
    BEGIN java.util.Date#hashCode()
    BEGIN java.util.Date#getTime()
    END java.util.Date#getTime() : 0
    END java.util.Date#hashCode() : 0
    BEGIN java.util.Date#getTime()
    END java.util.Date#getTime() : 0
    

    組件中也可以設(shè)定InterType的適用情況。比如,在Hoge中設(shè)定PropertyInterType的適用情況如下進(jìn)行。

    <components>
        <include path="aop.dicon"/>
        <component class="examples.Hoge">
            <interType>aop.propertyInterType</aspect>
        </component>
    </components>
    

    在interType標(biāo)簽的正文中指定InterType的名稱。

    Meta數(shù)據(jù)

    在components、component、arg、property標(biāo)簽中也可以指定Meta數(shù)據(jù)。meta標(biāo)簽將作為需要指定Meta數(shù)據(jù)的標(biāo)簽的字標(biāo)簽來指定Meta數(shù)據(jù)。例如,想要在components標(biāo)簽中指定Meta數(shù)據(jù)的情況時(shí),象下面一樣設(shè)定。

    <components>
        <meta name="aaa">111</meta>
    </components>
    

    request的自動(dòng)綁定

    對(duì)于組件來說,也可以進(jìn)行HttpServletRequest的自動(dòng)綁定。為了實(shí)現(xiàn)這個(gè)目的,在組件中,定義了setRequest(HttpServletRequest request)方法。這樣的話,S2Container就自動(dòng)得設(shè)定了request。還有,需要象下面這樣在web.xml中進(jìn)行Filter的定義。

    <web-app>
    <filter>
    <filter-name>s2filter</filter-name>
    <filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
    </filter>

    <filter-mapping>
    <filter-name>s2filter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-app>

    同樣地對(duì)HttpServletResponse、HttpSession、ServletContext也是只要定義了setter方法,就可以自動(dòng)綁定了。而且,使用了S2ContainerFilter的話,HttpServletRequest、HttpServletResponse、HttpSession、ServletContext就可以各自用request、response、session、application的名字來做為組件被自由訪問了。

    組件的自動(dòng)注冊(cè)

    根據(jù)自動(dòng)綁定的原理,DI的設(shè)定幾乎可以做近乎全部的自動(dòng)化。 使用備注碼就有可能進(jìn)行更加細(xì)致的設(shè)定。 更進(jìn)一步、對(duì)組件的注冊(cè)也進(jìn)行自動(dòng)化的話,就可以稱為組件的自動(dòng)注冊(cè)機(jī)能了。

    org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister

    是從文件系統(tǒng)中將類檢索出來對(duì)組件進(jìn)行自動(dòng)注冊(cè)的組件。

    屬性說明
    instanceDef在自動(dòng)注冊(cè)的組件中指定適用的InstanceDef。用XML指定的場合下,
    @org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST
    這樣來指定。
    autoBindingDef在自動(dòng)注冊(cè)的組件中指定適用的AutoBindingDef。用XML指定的場合下,
    @org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
    這樣來指定。
    autoNaming可以根據(jù)類名來自動(dòng)決定組件名的組件。需要實(shí)裝 org.seasar.framework.container.autoregister.AutoNaming interface。默認(rèn)狀態(tài)下,使用org.seasar.framework.container.autoregister.DefaultAutoNaming類的實(shí)例。

    方法說明
    addClassPattern將想要自動(dòng)注冊(cè)的類模式注冊(cè)。最開始的一個(gè)參數(shù)是組件所在包的名字。子包也能被以回歸的方式進(jìn)行檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”分隔做復(fù)數(shù)個(gè)設(shè)定。
    addIgnoreClassPattern將不想自動(dòng)注冊(cè)的類模式注冊(cè)。最開始的一個(gè)參數(shù)是組件所在包的名字。子包也能被以回歸的方式進(jìn)行檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”分隔做復(fù)數(shù)個(gè)設(shè)定。
    org.seasar.framework.container.autoregister.JarComponentAutoRegister

    從Jar文件中檢索類自動(dòng)注冊(cè)組件的組件。

    屬性說明
    jarFileNames指定設(shè)定對(duì)象的jar文件名。可以使用正則表達(dá)式。但是能包含后綴。指定復(fù)數(shù)個(gè)對(duì)象的場合下,用“,”做分割符。例如,myapp.*, yourapp.*這樣。
    referenceClass用這個(gè)屬性指定的類所屬的jar文件的父路徑為基礎(chǔ)路徑(例如,WEB-INF/lib)。默認(rèn)的是org.aopalliance.intercept.MethodInterceptor.class。
    instanceDef適用于自動(dòng)注冊(cè)的組件的InstanceDef的指定。在XML中如下,
    @org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST
    這樣指定。
    autoBindingDef適用于自動(dòng)注冊(cè)的組件的AutoBindingDef的指定。在XML中如下,
    @org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
    這樣指定。
    autoNaming根據(jù)類名自動(dòng)決定組件的名稱的組件。需要對(duì)org.seasar.framework.container.autoregister.AutoNaming interface 進(jìn)行實(shí)裝。默認(rèn)的情況下是org.seasar.framework.container.autoregister.DefaultAutoNaming類的實(shí)例。

    方法說明
    addClassPattern將想要自動(dòng)注冊(cè)的類模式注冊(cè)。最開始的一個(gè)參數(shù)是組件所在包的名字。子包也能被以回歸的方式進(jìn)行檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”分隔做復(fù)數(shù)個(gè)設(shè)定。
    addIgnoreClassPattern將不想自動(dòng)注冊(cè)的類模式注冊(cè)。最開始的一個(gè)參數(shù)是組件所在包的名字。子包也能被以回歸的方式進(jìn)行檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”分隔做復(fù)數(shù)個(gè)設(shè)定。
    org.seasar.framework.container.autoregister.ComponentAutoRegister

    將類從文件系統(tǒng)或者Jar文件中檢索出來并將組件自動(dòng)注冊(cè)的組件。

    屬性說明
    instanceDef適用于自動(dòng)注冊(cè)的組件的InstanceDef的指定。在XML中如下,@org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST這樣指定。
    autoBindingDef適用于自動(dòng)注冊(cè)的組件的AutoBindingDef的指定。在XML中如下,
    @org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
    這樣指定。
    autoNaming從類的名稱來自動(dòng)決定組件的名稱的組件。需要對(duì)org.seasar.framework.container.autoregister.AutoNaming instance進(jìn)行實(shí)裝。默認(rèn)的是 org.seasar.framework.container.autoregister.DefaultAutoNaming類的實(shí)例。

    方法說明
    addReferenceClass以這個(gè)方法所指定的類所存在的路徑或者Jar文件為基點(diǎn)對(duì)類進(jìn)行檢索。
    addClassPattern將想要自動(dòng)注冊(cè)的類模式注冊(cè)。最開始的一個(gè)參數(shù)是組件所在包的名字。子包也能被以回歸的方式進(jìn)行檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”分隔做復(fù)數(shù)個(gè)設(shè)定。
    addIgnoreClassPattern將不想 自動(dòng)注冊(cè)的類模式注冊(cè)。最開始的一個(gè)參數(shù)是組件所在包的名字。子包也能被以回歸的方式進(jìn)行檢索。第二個(gè)參數(shù)是類的名字。可以使用正則表達(dá)式。也可以用“,”分隔做復(fù)數(shù)個(gè)設(shè)定。

    AutoNaming

    根據(jù)AutoNaming來控制組件名稱。

    org.seasar.framework.container.autoregister.DefaultAutoNaming

    從類的完整合法名稱中將類的包的那部分名稱去掉,如果結(jié)尾是Impl或者Bean也要去掉,之后將開頭的字母變成小寫做為組件名稱來設(shè)定。 例如,aaa.HogeImpl類的情況下,組件的名稱就成了hoge。

    屬性說明
    decapitalize組件名的開頭字母為小寫的情況下指定為true。默認(rèn)值是true。

    方法說明
    setCustomizedName不依從于默認(rèn)的規(guī)則對(duì)類進(jìn)行注冊(cè)。第一個(gè)參數(shù)是類的完整合法名。第二個(gè)參數(shù)是組件的名稱。
    addIgnoreClassSuffix指定從類名的尾端消除的部分。注冊(cè)默認(rèn)值為Impl以及Bean。
    addReplaceRule根據(jù)正則表達(dá)式追加替換規(guī)則。第一個(gè)參數(shù)為正則表達(dá)式。第二個(gè)參數(shù)為向要替換的字符串。
    clearReplaceRule用setCustomizedName、addIgnoreClassSuffix、addReplaceRule將注冊(cè)的變換規(guī)則清零。作為默認(rèn)值被注冊(cè)的Impl和Bean也被清零。
    org.seasar.framework.container.autoregister.QualifiedAutoNaming

    將包的名字或者是一部分類的合法名做為組件名稱的設(shè)定。從類的完整合法名的最后把Impl或者Bean去掉,開頭字母小寫,分隔點(diǎn)后緊接著的字母變成大寫并取掉分隔點(diǎn),將這個(gè)新的單詞設(shè)定為組件的名稱。
    可以將包的開頭的不要的部分做消除指定。
    例如,aaa.bbb.ccc.ddd.HogeImpl類的情況下,將開頭的aaa.bbb做消除指定的情況下組件的名稱為,cccDddHogeになります。

    屬性說明
    decapitalize組件名的開頭字母為小寫的情況下指定為true。默認(rèn)值是true。

    方法說明
    setCustomizedName遵從默認(rèn)的規(guī)則來注冊(cè)類。第一個(gè)參數(shù)是類的完整合法名。 第二個(gè)參數(shù)是組件的名稱。
    addIgnorePackagePrefix從包名稱的開頭開始指定消除的部分。
    addIgnoreClassSuffix類名稱的最末尾開始指定消除的部分。默認(rèn)地將Impl和Bean注冊(cè)。
    addReplaceRule根據(jù)正則表達(dá)式追加替換規(guī)則。第一個(gè)參數(shù)為正則表達(dá)式。第二個(gè)參數(shù)是替換的新字符串。
    clearReplaceRule將setCustomizedName、 addIgnorePackagePrefix、 addIgnoreClassSuffix、 addReplaceRule注冊(cè)的替換規(guī)則清除。默認(rèn)注冊(cè)的Impl以及Bean也將被清除。
    <component
      class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
        <property name="autoNaming">
            <component class="org.seasar.framework.container.autoregister.DefaultAutoNaming">
                <initMethod name="setCustomizedName">
                    <arg>"examples.di.impl.HogeImpl"</arg>
                    <arg>"hoge2"</arg>
                </initMethod>
            </component>
        </property>
        <initMethod name="addClassPattern">
            <arg>"examples.di.impl"</arg>
            <arg>".*Impl"</arg>
        </initMethod>
    </component>
    
    <component class="org.seasar.framework.container.autoregister.JarComponentAutoRegister">
        <property name="referenceClass">
            @junit.framework.TestSuite@class
        </property>
        <property name="jarFileNames">"junit.*"</property>
        <initMethod name="addClassPattern">
            <arg>"junit.framework"</arg>
            <arg>"TestSuite"</arg>
        </initMethod>
    </component>
    
    <component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
        <initMethod name="addReferenceClass">
            <arg>@aaa.bbb.ccc.ddd.HogeImpl@class</arg>
        </initMethod>
        <initMethod name="addClassPattern">
            <arg>"aaa.bbb"</arg>
            <arg>".*Impl"</arg>
        </initMethod>
    </component>
    

    AOP的自動(dòng)注冊(cè)

    根據(jù)組件的自動(dòng)注冊(cè)規(guī)則,組件的注冊(cè)可以做到自動(dòng)化。進(jìn)一步,AOP的注冊(cè)也可以做到自動(dòng)化,這就是AOP的自動(dòng)注冊(cè)機(jī)能。

    和組件的自動(dòng)注冊(cè)功能組和使用的場合下,必須在組件的自動(dòng)注冊(cè)設(shè)定之后,作AOP的自動(dòng)注冊(cè)的設(shè)定。對(duì)于適用于使用AOP的組件的記述,必須在AOP的自動(dòng)注冊(cè)設(shè)定之后進(jìn)行。

    <components>
        <!-- 1.組件的自動(dòng)注冊(cè) -->
        <component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
            ...
        </component>
    
        <!-- 2.AOP的自動(dòng)注冊(cè) -->
        <component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
            ...
        </component>
    
        <!-- 3.其它的組件 -->
        <component class="...">
            ...
        </component>
        ...
    <components>
    
    org.seasar.framework.container.autoregister.AspectAutoRegister

    通過指定類名的模式來進(jìn)行AOP的自動(dòng)注冊(cè)的組件。

    屬性說明
    interceptor指定interceptor。想要指定復(fù)數(shù)個(gè)interceptor的場合下,請(qǐng)使用InterceptorChain
    pointcut適于使用interceptor的方法用逗號(hào)分隔開進(jìn)行指定。不指定pointcut的情況下,實(shí)裝組件的interface的所有方法都做為interceptor的對(duì)象。對(duì)于方法名稱也可以使用正則表達(dá)式(JDK1.4のregex)來指定。

    方法說明
    addClassPattern將想要自動(dòng)注冊(cè)的類的模式注冊(cè)。第一個(gè)參數(shù)是組件的包的名。子包也可以用回歸的方法檢索。第二個(gè)參數(shù)是類名。可以使用正則表達(dá)式。用“,”分隔可以做復(fù)數(shù)個(gè)記述。
    addIgnoreClassPattern將不想自動(dòng)注冊(cè)的類模式注冊(cè)。第一個(gè)參數(shù)是組件的包的名。子包也可以用回歸的方法檢索。第二個(gè)參數(shù)是類名。可以使用正則表達(dá)式。用“,”分隔可以做復(fù)數(shù)個(gè)記述。

    <include path="aop.dicon"/>
    ...
    <component
    class="org.seasar.framework.container.autoregister.AspectAutoRegister">
    <property name="interceptor">aop.traceInterceptor</property>
    <initMethod name="addClassPattern">
    <arg>"examples.di.impl"</arg>
    <arg>".*Impl"</arg>
    </initMethod>
    </component>
    org.seasar.framework.container.autoregister.InterfaceAspectAutoRegister

    針對(duì)某個(gè)interface的實(shí)裝類進(jìn)行AOP的自動(dòng)注冊(cè)的組件。

    屬性說明
    interceptor指定interceptor。想要指定復(fù)數(shù)個(gè)interceptor的場合下,請(qǐng)使用InterceptorChain
    targetInterface針對(duì)某一指定的interface的實(shí)裝組件,使用AOP。
    <include path="aop.dicon"/>
    ...
    <component
    class="org.seasar.framework.container.autoregister.InterfaceAspectAutoRegister">
    <property name="interceptor">aop.traceInterceptor</property> <property name="targetInterface">@examples.Greeing@class</property>
    </component>

    META的自動(dòng)注冊(cè)

    META信息也可以自動(dòng)注冊(cè)。

    同組件的自動(dòng)注冊(cè)相組合使用的場合下,必須在組件的自動(dòng)注冊(cè)設(shè)定之后,做META的自動(dòng)注冊(cè)的設(shè)定記述。 調(diào)用META信息的組件必須在META自動(dòng)注冊(cè)的設(shè)定之后記述。

    <components>
        <!-- 1.組件的自動(dòng)注冊(cè) -->
        <component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
            ...
        </component>
    
        <!-- 2.META的自動(dòng)注冊(cè) -->
        <component class="org.seasar.framework.container.autoregister.MetaAutoRegister">
            ...
        </component>
    
        <!-- 3.其它的組件 -->
        <component class="...">
            ...
        </component>
        ...
    <components>
    
    org.seasar.framework.container.autoregister.MetaAutoRegister

    通過指定類名的模式來做META自動(dòng)注冊(cè)的組件。
    被自動(dòng)注冊(cè)的META數(shù)據(jù),將做為在這個(gè)組件自身的定義中一個(gè)叫做autoRegister的META數(shù)據(jù)的子數(shù)據(jù)來記述。

    方法說明
    addClassPattern將想要自動(dòng)注冊(cè)的類模式注冊(cè)。第一個(gè)參數(shù)是組件所在包的名字。子包也將被用回歸的方式所檢索。第二個(gè)參數(shù)是類名。可以使用正則表達(dá)式。用“,”做分隔符號(hào),可以做復(fù)數(shù)個(gè)記述。
    addIgnoreClassPattern將不想自動(dòng)注冊(cè)的類模式注冊(cè)。第一個(gè)參數(shù)是組件所在包的名字。子包也將被用回歸的方式所檢索。第二個(gè)參數(shù)是類名。可以使用正則表達(dá)式。用“,”做分隔符號(hào),可以做復(fù)數(shù)個(gè)記述。
    <component
      class="org.seasar.framework.container.autoregister.MetaAutoRegister">
        <meta name="autoRegister">
            <meta name="hoge"</meta>
        </meta>
        <initMethod name="addClassPattern">
            <arg>"examples.di.impl"</arg>
            <arg>".*Impl"</arg>
        </initMethod>
    </component>
    

    本例中、叫做hoge的META數(shù)據(jù)自動(dòng)地注冊(cè)到其它的組件定義中。

    Hotswap

    一直以來,更改了源代碼并重新編譯之后的場合,想要測試編譯后的機(jī)能,必須讓應(yīng)用程序(確切地說是ClassLoader)再起動(dòng)。在應(yīng)用程序服務(wù)器上,進(jìn)行程序再起動(dòng)將非常花時(shí)間。 “真煩人”這樣想的人很多不是嗎。

    在Seasar2中,應(yīng)用程序在運(yùn)行中,即使類文件替換了,也可以即刻測試的Hotswap機(jī)能得以實(shí)現(xiàn)。這樣就讓我們從那種“心情煩躁”中解放出來了。無須花費(fèi)多余的時(shí)間使得出產(chǎn)率得以提高。這樣的好東西,不想試一試嗎?

    Greeting.java

    package examples.hotswap;
    
    public interface Greeting {
    
        String greet();
    }
    

    GreetingImpl.java

    package examples.hotswap.impl;
    
    import examples.hotswap.Greeting;
    
    public class GreetingImpl implements Greeting {
    
        public String greet() {
            return "Hello";
        }
    }
    

    hotswap.dicon

    <components>
    <component class="examples.hotswap.impl.GreetingImpl"/>
    </components>

    到此為止,并沒有什么特別的變化。關(guān)鍵點(diǎn)從此開始。 使用s2container.dicon,切換成hotswap模式。

    s2container.dicon

    <components>
    <component
    class="org.seasar.framework.container.factory.S2ContainerFactory$DefaultProvider">
    <property name="hotswapMode">true</property>
    </component>
    </components>

    把s2container.dicon根據(jù)class path放到根路徑下的話,就能被自動(dòng)識(shí)別到。也可以使用S2ContainerFactory#configure()明確地指定。

    GreetingMain.dicon

    package examples.hotswap.main;
    
    import org.seasar.framework.container.S2Container;
    import org.seasar.framework.container.factory.S2ContainerFactory;
    
    import examples.hotswap.Greeting;
    
    public class GreetingMain {
    
        private static final String CONFIGURE_PATH =
            "examples/hotswap/dicon/s2container.dicon";
    
        private static final String PATH =
            "examples/hotswap/dicon/hotswap.dicon";
    
        public static void main(String[] args) throws Exception {
            S2ContainerFactory.configure(CONFIGURE_PATH);
            S2Container container = S2ContainerFactory.create(PATH);
            System.out.println("hotswapMode:" + container.isHotswapMode());
            container.init();
            try {
                Greeting greeting = (Greeting) container
                        .getComponent(Greeting.class);
                System.out.println(greeting.greet());
                System.out.println("Let's modify GreetingImpl, then press ENTER.");
                System.in.read();
                System.out.println("after modify");
                System.out.println(greeting.greet());
            } finally {
                container.destroy();
            }
        }
    }
    

    為了使用hotswap,有必要調(diào)用S2Container#init()。 執(zhí)行了的話"Hello"表示出來后,程序就停止了,所以將GreetingImpl#greet()修改并編譯使之表示"Hello2"。這之后,請(qǐng)將文字終端顯示窗口調(diào)成聚焦?fàn)顟B(tài)并按下ENTER鍵。雖然是用同一個(gè)instance也沒有關(guān)系,class文件被替換了的事實(shí)可以很容易的被測知。這個(gè)是實(shí)例模式為singleton的場合下的例子,實(shí)例模式為prototype的場合下,類將在調(diào)用S2Container#getComponent()的時(shí)刻被置換。

    執(zhí)行結(jié)果

    hotswapMode:true
    Hello
    Let's modify GreetingImpl, then press ENTER.
    
    after modify
    Hello2
    

    為了使用hotswap,組件提供了interface,組件的利用者方面,必須通過interface來利用組件。 實(shí)例模式為request、session的情況下,對(duì)于一個(gè)組件不能被其它的組件調(diào)用的場合來說,沒有interface也可以利用hotswap。

    S2Container標(biāo)簽參考

    DOCTYPE

    DOCTYPE要在XML聲明之后指定。請(qǐng)象下面那樣指定。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components>
        <component name="hello" class="examples.dicon.HelloConstructorInjection">
            <arg>"Hello World!"</arg>
        </component>
    </components>
    

    components標(biāo)簽(必須)

    成為了根標(biāo)簽。

    namespace屬性(任意)

    可以指定命名空間。做為Java的標(biāo)識(shí)語來使用

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components namespace="hoge">
        ...
    </components>
    

    include標(biāo)簽(任意)

    將被分割的S2Container的定義讀入的情況下使用。

    path屬性(必須)

    可以指定定義文件的路徑。相對(duì)于CLASSPATH所指定的路徑為根的絕對(duì)路徑。例如,WEB-INF/classes/aaa.dicon的情況下就指定為aaa.dicon 、WEB-INF/classes/aaa/bbb/ccc.dicon 的情況下就指定為 aaa/bbb/ccc.dicon 路徑分隔符在Windows下Unix下都是/。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components>
        <include path="aaa/bbb/ccc.dicon" />
    </components>
    

    component標(biāo)簽(任意)

    定義組件。

    class屬性(任意)

    指定類的完整合法名。在正文中,是用了OGNL式來指定組件的場合下,class的屬性可以被省略。使用OGNL式來指定類的屬性的時(shí)候,需要進(jìn)行類型檢查。

    name屬性(任意)

    指定名稱也可以。將做為Java的標(biāo)示語來使用。詳細(xì)情況請(qǐng)參照組件的取得

    instance屬性(任意)

    可以指定讓S2Container對(duì)組件的實(shí)例如進(jìn)行管理。可以指定singleton(默認(rèn))、prototype、outer、request、session幾種類型。更詳細(xì)的請(qǐng)參照實(shí)例管理

    autoBinding屬性(任意)

    S2Container可以指定如何解決組件之間的依存關(guān)系。有auto(默認(rèn))、constructor、property、none幾種類型。詳細(xì),請(qǐng)參照自動(dòng)綁定

    arg標(biāo)簽(任意)

    做為component標(biāo)簽的子標(biāo)簽來使用的場合下,就成了構(gòu)造函數(shù)的參數(shù)。根據(jù)記述的順序傳給構(gòu)造函數(shù)。 做為initMethod標(biāo)簽destroyMethod標(biāo)簽的子標(biāo)簽被使用的場合下,就成了方法函數(shù)的參數(shù)。按照記述的順序傳給方法函數(shù)。 做為參數(shù)被傳遞的實(shí)際值,要么在正文中使用OGNL式指定,要么在子標(biāo)簽中使用component標(biāo)簽指定。

    property標(biāo)簽(任意)

    做為component標(biāo)簽的子標(biāo)簽來使用。做為屬性變量被設(shè)定的實(shí)際值,要么在正文中使用OGNL式指定,要么在子標(biāo)簽中使用component標(biāo)簽指定。

    name屬性(必須)

    指定屬性變量名。

    bindingType屬性(任意)

    可以根據(jù)每一個(gè)屬性變量進(jìn)行細(xì)致的自動(dòng)綁定控制。must、should(默認(rèn))、may、none幾個(gè)類型可以用來指定。詳細(xì)請(qǐng)參照自動(dòng)綁定

    meta標(biāo)簽(任意)

    做為components標(biāo)簽component標(biāo)簽arg標(biāo)簽property標(biāo)簽的子標(biāo)簽來使用。META數(shù)據(jù)的值,要么在正文中使用OGNL式指定,要么在子標(biāo)簽中使用component標(biāo)簽指定。

    name屬性(任意)

    指定META名。

    initMethod標(biāo)簽(任意)

    做為component標(biāo)簽的子標(biāo)簽使用。參數(shù),在子標(biāo)簽中,使用arg標(biāo)簽指定。無須寫出name屬性,使用OGNL式也可以調(diào)用組件的方法。定義了initMethod標(biāo)簽的組件將做為表示組件自身#self、表示System.out#out、表示System.err#err等僅在initMethod標(biāo)簽內(nèi)部有效的對(duì)象來使用。

    name屬性(任意)

    指定方法名。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
    "http://www.seasar.org/dtd/components23.dtd">
    <components>
        <component class="java.util.HashMap">
            <initMethod name="put">
                <arg>"aaa"</arg>
                <arg>111</arg>
            </initMethod>
            <initMethod>#self.put("aaa", 111)</initMethod>
            <initMethod>#out.println("Hello")</initMethod>
        </component>
    </components>
    

    destroyMethod標(biāo)簽(任意)

    和initMethod標(biāo)簽一樣。

    aspect標(biāo)簽(任意)

    將AOP組入到組件的定義中。詳細(xì)請(qǐng)參照S2AOP的aspect標(biāo)簽的說明。

    interType標(biāo)簽(任意)

    象組件中組入interType。詳請(qǐng)請(qǐng)參照S2AOP的interType標(biāo)簽的說明。

    description標(biāo)簽(任意)

    做為components標(biāo)簽component標(biāo)簽arg標(biāo)簽property標(biāo)簽的子標(biāo)簽可以使用description標(biāo)簽。可以自由地記述說明。

    OGNL式

    在S2Container中,做為表達(dá)式語言可以利用

  • char是象'a'一樣用'括起來。
  • 數(shù)值就像123這樣直接記述。
  • 倫理值就直接向true,false這樣記述。
  • new java.util.Date(0)這樣可以用類的完整合法限定名來直接調(diào)用其構(gòu)造函數(shù)。
  • @java.lang.Math@max(1, 2)這樣可以調(diào)用static方法的直接呼出結(jié)果。
  • @java.lang.String@class這樣可以直接調(diào)用類。
  • hoge.toString()這樣可以參照組件的方法調(diào)用結(jié)果。本例中,前提是在某個(gè)地方已經(jīng)定義了叫做hoge的組件。
  • 詳細(xì)請(qǐng)參照OGNL指南

    S2Container備注碼參考

    在S2Container中,做為備注碼的實(shí)裝方法,準(zhǔn)備了Tiger備注碼?backport175備注碼?定數(shù)備注碼共3個(gè)種類。一般說起備注碼的話,都是指從Java 5導(dǎo)入的Tiger備注碼,但是僅僅如此的話,JDK1.4的使用者將不可能利用這一個(gè)特性了。

    為了盡可能地讓更多的人樂意方便地使用備注碼,在JDK1.4中,可以使用Tiger風(fēng)格的備注碼(JSR-175) backport175備注碼,是利用public static final這樣的常量定義來完成備注碼功能的。

    Component備注碼

    backport175備注碼的利用方式如下。

    /**
     * @org.seasar.framework.container.annotation.backport175.Component(
     *      name = "xxx",
     *      instance = "prototype",
     *      autoBinding = "property")
     */
    public class Xxx {
        ...
    }
    

    常量備注碼的利用方式如下。

    public static final String COMPONENT =
      "name = xxx, instance = prototype, autoBinding = property";
    

    Binding備注碼

    backport175方式的備注碼如下。

    /**
    
     * @org.seasar.framework.container.annotation.backport175.Binding("aaa2")
     */
    public void setAaa(String aaa) {
        ...
    }
    
    /**
     * @org.seasar.framework.container.annotation.backport175.Binding(bindingType="none")
     */
    public void setBbb(String bbb) {
        ...
    }
    
    /**
     * @org.seasar.framework.container.annotation.backport175.Binding
     */
    public void setCcc(String ccc) {
        ...
    }
    

    常量備注碼要用屬性變量名_BINDING這樣來指定。

    public static final String aaa_BINDING = "aaa2";
    
    public static final String bbb_BINDING = "bindingType=none";
    
    public static final String ccc_BINDING = null;
    
    public void setAaa(Aaa aaa) {
        ...
    }
    
    public void setBbb(Bbb bbb) {
        ...
    }
    
    public void setCcc(Ccc ccc) {
        ...
    }
    

    Aspect備注碼

    aspect標(biāo)簽的替代使用方法是、Aspect備注碼。與aspect標(biāo)簽不同,因?yàn)榭梢远x復(fù)數(shù)個(gè)定義? 想要適用于復(fù)數(shù)個(gè)intercepter的情況下?請(qǐng)使用

    backport175方式的備注碼如下。

    /**
     * @org.seasar.framework.container.annotation.backport175.Aspect(
     *  "aop.traceInterceptor")
     */
    public class Xxx {
        ...
    }
    
    public class Xxx {
        ...
        /**
         * @org.seasar.framework.container.annotation.backport175.Aspect(
         *  "aop.traceInterceptor")
         */
        public void hoge() {
            ...
        }
    }
    

    常量備注碼的形式如下。想要指定復(fù)數(shù)個(gè)pointcut的情況下,請(qǐng)象pointcut= get.*\nexecute.*這樣用\n做分隔。 不能使用\n之外的其它分隔文字。

    public static final String ASPECT =
        "value=aop.traceInterceptor, pointcut=getAaa";
    

    InterType備注碼

    backport175方式的備注碼如下。

    /**
     * @org.seasar.framework.container.annotation.backport175.InterType(
     *  {"aop.propertyInterType", "aop.someInterType"})
     */
    public class Xxx {
        ...
    }
    

    常量方式的備注碼如下。

    public static final String INTER_TYPE =
        "aop.propertyInterType, aop.someInterType";
    

    InitMethod備注碼

    initMethod標(biāo)簽的代替使用方法是InitMethod備注碼。 與initMethod標(biāo)簽不同,OGNL式的使用和參數(shù)的設(shè)定都不可以。

    Tiger方式的備注碼如下。

    public class Xxx {
        ...
        @InitMethod
        public void init() {
            ...
        }
    }
    

    backport175方式的備注碼如下。

    public class Xxx {
        ...
        /**
         * @org.seasar.framework.container.annotation.backport175.InitMethod
         */
        public void init() {
            ...
        }
    }
    

    常量方式的備注碼如下。想要指定復(fù)數(shù)個(gè)初始化方法的情況下,請(qǐng)用逗號(hào)(,)做分隔符。

    public static final String INIT_METHOD = "init";
    

    DestroyMethod備注碼

    destroyMethod標(biāo)簽的替代使用方式是DestroyMethod備注碼。 與destroyMethod標(biāo)簽不同,OGNL式的使用,參數(shù)的設(shè)定都不可以。

    Tiger方式的備注碼如下。

    public class Xxx {
        ...
        @DestroyMethod
        public void destroy() {
            ...
        }
    }
    

    backport175方式的備注碼如下。

    public class Xxx {
        ...
        /**
         * @org.seasar.framework.container.annotation.backport175.DestroyMethod
         */
        public void destroy() {
            ...
        }
    }
    

    常量備注碼如下。想要指定復(fù)數(shù)個(gè)初始化方法的情況下,請(qǐng)用逗號(hào)(,)做分隔符。

    public static final String DESTROY_METHOD = "destroy";
    


    posted on 2007-07-18 14:16 蠻哥♂楓 閱讀(24536) 評(píng)論(12)  編輯  收藏 所屬分類: JavaOpenSource

    FeedBack:
    # re: 小日本的開源框架 Seasar2
    2007-11-15 10:57 | lsd751@sohu.com
    挺好的。你自己從日文網(wǎng)站翻譯來的?  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2
    2007-11-30 16:25 | yinzi
    不錯(cuò),仔細(xì)學(xué)習(xí)了一下.  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2
    2007-12-13 20:37 |
    我最近在看它的文檔,是一個(gè)不錯(cuò)的東西,不過想s2dao之類的東西,最好還是別用,控制反轉(zhuǎn) 還是不錯(cuò),研究一下怎么用。
    jefnguo#gmail.com  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2
    2007-12-20 17:20 | manu
    小日本就喜歡搞點(diǎn)小把戲
      回復(fù)  更多評(píng)論
      
    # re: 日本的開源框架 Seasar2
    2008-07-23 09:29 | hai
    內(nèi)容很不錯(cuò)。可是題目能不能不要“小”字?
    上班時(shí)候看真不方便。萬一旁邊的同事懂點(diǎn)中國的事……

    ps: 如果是精神勝利法,沒有必要;如果是玩笑,也不應(yīng)該帶歧視性。  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2
    2008-12-08 11:56 | 拜訪
    不過,帶回家研究研究,謝謝你  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2
    2008-12-16 20:32 |
    寫的很詳細(xì),我這兩天一直在看,期待關(guān)于seasar新的文章  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2
    2008-12-25 22:50 | ln_xk
    我的項(xiàng)目一直在用它。不錯(cuò)的框架  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2[未登錄]
    2010-01-29 14:45 | x
    寫的很詳細(xì)。多謝。。  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2[未登錄]
    2011-12-26 11:52 | aaa
    @manu
    你有本事也搞一個(gè),人家能自己弄出來就很牛B了  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2[未登錄]
    2012-02-27 10:27 | 小菜鳥
    嗯 很詳細(xì)  回復(fù)  更多評(píng)論
      
    # re: 小日本的開源框架 Seasar2[未登錄]
    2012-09-14 14:26 | zhang
    主站蜘蛛池模板: 国产乱子伦精品免费视频| 一本色道久久88亚洲精品综合| 亚洲av无码成人黄网站在线观看| 午夜亚洲国产理论秋霞| 亚洲精品国产福利在线观看| 色在线亚洲视频www| 亚洲成av人片在www鸭子| 特色特黄a毛片高清免费观看| 亚洲精品视频免费观看| 91精品导航在线网址免费| 无码人妻久久一区二区三区免费丨| 日韩免费a级在线观看| 亚洲福利精品一区二区三区| 亚洲精品自在在线观看| 亚洲国产精品久久网午夜| 亚洲精品国产第一综合99久久| 国产精品免费久久久久久久久| 久久精品国产免费观看| 国产片免费在线观看| 亚洲精品无码久久久影院相关影片 | 国产精品午夜免费观看网站| 中文字幕无码日韩专区免费| 91成人免费在线视频| 免费国产成人午夜私人影视| 亚洲国产成人高清在线观看| 亚洲精品国产国语| XXX2高清在线观看免费视频| 免费人成在线观看69式小视频| 亚洲成网777777国产精品| 亚洲国产成人久久综合一| 亚洲国产欧美国产综合一区| 成人精品视频99在线观看免费| 麻豆视频免费播放| 亚洲国产精品视频| 亚洲免费电影网站| 一区二区三区免费视频播放器| 999在线视频精品免费播放观看| 亚洲国产精品毛片av不卡在线| 亚洲最大免费视频网| 一本岛v免费不卡一二三区| 久草视频免费在线观看|