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

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

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

          下面簡單介紹一下:

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

          為了不用寫設定文件也能夠運行,Convention over Configuration的思想得以采用。Convention over Configuration就是指,“只要遵守一個適當的規約,即使不用進行非常麻煩的設定,框架結構也可以自動替我們搞定的思想”,這一思想是Ruby on Rails中所倡導的。Seasar2的Convention over Configuration是從Ruby on Rails 那里得到的提示而產生的。

          使用Seasar2的話,對于僅僅需要維護數據表這樣簡單的應用,可以在不到3分鐘的時間里作成。

          應用程序發生改動之時也無需啟動便可立即識別變更的機能在Seasar2里被稱為HOT deploy



          安裝:

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

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

          使用Seasar2基本功能(S2Container, S2AOP)的時候、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 (任選項)
          • lib/log4j-1.2.13.jar (任選項)
          • resources/log4j.properties (任選項)
          • resources/aop.dicon (任選項)

          使用Seasar2的擴張機能(S2JTA, S2DBCP, S2JDBC, S2Unit, S2Tx, S2DataSet)的時候必須要將以下文件追加到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

          根據應用軟件所需的執行環境、選擇以下需要引用的文件[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]

          環境geronimo-j2ee_1.4_spec-1.0.jargeronimo-jta_1.1_spec-1.0.jargeronimo-ejb_2.1_spec-1.0.jar
          不完全對應J2EE的Servlet container
          (Tomcat等)
          不要
          (使用S2JTA,S2Tx的時候)

          (使用S2Tiger的時候)
          完全對應J2EE的應用服務器
          (JBoss, WebSphere, WebLogic等)
          不要不要不要
          獨立
          (使用S2JTA,S2Tx時候)
          不要不要

          為了讓大家更簡單的體驗數據庫機能、使用了HSQLDB作為RDBMS。為了能夠體驗Oracle機能、準備了hsql/sql/demo-oracle.sql。SQL*Plus等執行了之后、請根據環境的需要改寫jdbc.dicon的XADataSourceImpl的設定項目

          請使用S2Container用的插件Kijimuna

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

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

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

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

          ?

          快速上手

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

          最初的一步

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

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

          問侯語的Interface。

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

          問候語的實裝。

          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

          使用問候語的客戶端的實裝。不是直接使用這個GreetngImpl(實裝),而是通過Greeting(Interface)來實現問候的機能。

          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());
              }
          }
          

          機能提供端和使用端的準備都完成了。下面我們就執行一下試試吧。

          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();
              }
          }
          

          實行結果如下。

          Hello World!
          

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

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

          那么,讓我們試著把剛才的提到的那個設定文件的內容寫一下。S2Container中,設定文件的后綴是".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"/>

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

          Greeting greeting = new GreetingImpl();
          

          component標簽的name屬性指定了組件的名稱,class屬性指定了組件的Java類文件名。下文就是greetingClient的設定。

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

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

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

          利用S2Container的起動類的內容如下。

          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)做成的。更加詳細的內容請參照S2Container的生成

          組件(greetingClient),是由S2Container#getComponent(String componentName)的方法取得的。詳細內容請參照組件的取得

          實行結果同先前一樣表示如下。

          Hello World!
          

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

          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中,經常使用的AOP模塊在aop.dicon中預先定義。 象下面這樣、使用include標簽。 更加詳細的?敬請參照S2Container定義的分解和引入

          <include path="aop.dicon"/>
          

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

          <aspect>aop.traceInterceptor</aspect>
          

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

          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();
              }
          }
          

          執行結果如下。可以明白一點,沒有修改源代碼,日志就被輸出了。

          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的基本使用方法就被掌握了。

          更進一步

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

          就是說制定一個適當的規約,遵守這個規約的話?無需什么設定也可以運作。比如說,剛才的設定文件中,象下面這樣明確地指定屬性的部分存在著。

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

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

          雖然一說到規約就容易產生麻煩之類的想法,“推薦而已,如果遵守的話就能使開發愉快”的話,遵守規約的動機就產生了。這才是問題的重點。

          如上的設定,可以做如下化簡

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

          實際上?剛才的AOP的例子也適用“Convention over Configuration”。 通常在AOP中,AOP的模塊在什么地方適用是由pointcut指定的,S2AOP的情況下? 如果遵守所謂“使用Interface”這個推薦的規約,不指定pointcut,自動的適用于在Interface中定義的所有方法。因為有這個機能,在剛才的那個例子中,就沒有必要指定pointcut。

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

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

          FileSystemComponentAutoRegister組件將addClassPattern方法指定的類從文件系統中探尋出來,自動注冊到S2Container中。關于initMethod標簽,請參照方法函數注入

          addClassPattern方法的第一個參數是想要注冊的組件的包的名字。 子包的內容也會用回歸的方式檢索。第二個參數是類的名字。可以使用正則表達式。也可以用“,”做分隔符指定復數個設定。

          根據組件自動注冊原則,即使后續追加組件的情況下,也沒有必要追加設定,這樣手續就大大地簡化了。

          如果組件的自動化注冊可以了,接下來就會想讓AOP的注冊也自動化了吧。剛才的GreetingImpl、GreetingClientImp的AOP注冊自動化的設定如下。

          <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方法同組件的自動化注冊時的用法一樣,這里就不做特殊的說明了。 組件自動化注冊和AOP自動化注冊的例子如下。

          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>

          那么來執行一下GreetingMain4吧。 自動注冊的情況下,S2Container#init()和S2Container#destroy()的調用是必要的。

          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();
                  }
              }
          }
          

          執行的結果同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
          

          大多數的情況下?自動注冊和自動綁定的組合方式都能順利的進行下去。不想要自動注冊的組件存在的情況下,自動注冊組件中準備了addIgnoreClassPattern方法,可以指定自動注冊外的組件。

          不想要自動綁定的屬性存在的情況下,使用Binding備注碼,不使用設定文件也可以做細節的調整。

          使用Hotswap的話?應用程序在運行中重新書寫更換類文件,馬上就能夠直接測試結果。不需要一個一個地將應用程序在啟動,因此開發的效率能夠得到大幅度的提高。

          現在,關于S2Container的高級使用方法也可以掌握了。這之后嘛,只要根據需要參照對應的操作手冊就可以了。

          S2Container參考

          需要作成的文件

          為了使用S2Container,定義文件的做成是必要的。定義文件就像是為了組織組件而制作的設計書一樣的東西。形式為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做成的時候、請將前述例子拷貝粘貼。根是components標簽。每一個組件用component標簽定義。用component標簽的class屬性指定組件的類的全名。在name屬性中、指定組件的名稱。詳細內容請參照S2Container定義標簽參考

          <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();
          

          定義文件的路徑需要被指定的情況下應在調用init()之前執行如下方法。

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

          參數path是相對于以CLASSPATH指定的路徑為根的定義文件的絕對路徑。例如,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生成之后需要許呼叫下一個方法。

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

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

          用這個方法取得的組件的實例,有必要進行在應用中的管理。

          組件的取得

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

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

          參數中指定的是組件的類或者是組件的名稱。詳細的請參照component標簽。要指定組件的類,只要是 組件 instanceof 類 的操作返回為true的類就能夠指定。但是、S2Container中所指定的類對應了好幾個實裝的組件的時候,S2Container將不能判斷返回哪一個組件為好,這樣就會發生TooManyRegistrationRuntimeException。請指定實裝組件為唯一的類。也可以用組件名稱取得組件。這種情況下也是同樣,用一個名稱的復數個組件被注冊的情況下,將發生TooManyRegistrationRuntimeException。指定組件名的場合下,因為也可能發生拼寫錯誤,所以盡可能的指定組件的類為好。

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

          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中,組件的構成所必要的值是用構造函數來設定(Constructor Injection),還是用設定函數來設定(Setter Injection),或者是用初始化函數來設定(Method Injection),這樣進行分類。Method Injection是S2Container的本源。S2Container支持以上所有類型和混合類型。

          構造函數?注入

          對構造函數的參數進行DI,這就是構造函數注入。
          S2Container的定義文件中,記述如下內容。

          • 組件的指定
            組件,用component標簽來組建。用class指定對應的類。
            也可以用name屬性給組件起名稱。
          • 構造函數的參數的指定
            組件的構造函數的參數用component標簽的子標簽arg標簽來指定。
            值為字符串的時候,用雙引號(")括起來。
          <components>
              <component name="..." class="...">
                    <arg>...</arg>
              </component>
          </components>
          

          設定函數?注入

          設定函數注入是指對于任意一個屬性變量使用設定函數來行使DI。
          S2Container的定義文件中作如下內容的記述。

          • 組件的指定
            組件的指定同構造函數注入相同。
          • 屬性變量的指定
            組件的屬性變量用component標簽的子標簽property來指定。
            用name屬性來指定變量的名稱。
          <components>
              <component name="..." class="...">
                    <property name="...">...</property>
              </component>
          </components>
          

          方法函數?注入

          方法函數注入是指,通過任意一個函數的調用來完成DI的功能。
          S2Container的定義文件中,記述如下內容。

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

          S2Container定義的分割和引入

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

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

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

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

          命名空間

          組件的定義被分割的情況下,為了不讓復數個組件的定義名稱發生沖突,可以用components標簽的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>
          

          在同一個組件定義文件中可以不需要指定命名空間而調用組件。調用其它S2Container文件中定義的組件時,要在組件名前加上命名空間。foo.aaa 和 bar.aaa 雖然有相同名稱的組件,但是因為命名空間的不同,就被認為是不同的組件。

          實例(instance)管理

          在S2Container中,怎么樣對實例進行管理,這個設定是用component標簽的instance屬性。

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

          生存周期

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

          <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>
          

          自動綁定

          組件間的依存關系,類型是interface的場合時,將由容器來自動解決。這是在S2Container被默認的,指定component標簽的autoBinding屬性可以進行更加細致的控制。

          autoBinding說明
          auto(default)適用于構造函數和屬性變量的自動綁定。
          constructor適用于構造函數的自動綁定。
          property適用于屬性變量的自動綁定。
          none只能對構造函數、屬性變量進行手動綁定。

          構造函數的自動綁定規則如下所示。

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

          屬性變量的自動綁定規則如下。

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

          用property標簽的bindingType屬性,可以更加細致的控制屬性變量。

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

          在組件中利用S2Container

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

          <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呢?為了達到這個目的,準備了以下的類。

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

          為了使用S2ContainerServlet,在web.xml中記述如下項目。

          <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中。對于S2ContainerServlet,為了比其它的servlet更早的起動,請做load-on-startup標簽的調整。S2ContainerServlet起動之后,可以用如下的方法函數取得S2Container的實例。

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

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

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

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

          app.dicon的角色

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

          AOP的適用

          在組件中AOP的適用情況也可以被設定。比如,想要在ArrayList中設定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標簽的正文中指定Interceptor的名字。pointcut的屬性中可以用逗號做分隔符指定AOP對象的方法的名字。pointcut的屬性沒有被指定的情況下,組件將把實裝的interface的所有方法函數作為AOP的對象。方法函數的名稱指定也可以用正則表達式(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();
          

          執行結果。

          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
          

          組件中也可以設定InterType的適用情況。比如,在Hoge中設定PropertyInterType的適用情況如下進行。

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

          在interType標簽的正文中指定InterType的名稱。

          Meta數據

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

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

          request的自動綁定

          對于組件來說,也可以進行HttpServletRequest的自動綁定。為了實現這個目的,在組件中,定義了setRequest(HttpServletRequest request)方法。這樣的話,S2Container就自動得設定了request。還有,需要象下面這樣在web.xml中進行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>

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

          組件的自動注冊

          根據自動綁定的原理,DI的設定幾乎可以做近乎全部的自動化。 使用備注碼就有可能進行更加細致的設定。 更進一步、對組件的注冊也進行自動化的話,就可以稱為組件的自動注冊機能了。

          org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister

          是從文件系統中將類檢索出來對組件進行自動注冊的組件。

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

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

          從Jar文件中檢索類自動注冊組件的組件。

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

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

          將類從文件系統或者Jar文件中檢索出來并將組件自動注冊的組件。

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

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

          AutoNaming

          根據AutoNaming來控制組件名稱。

          org.seasar.framework.container.autoregister.DefaultAutoNaming

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

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

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

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

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

          方法說明
          setCustomizedName遵從默認的規則來注冊類。第一個參數是類的完整合法名。 第二個參數是組件的名稱。
          addIgnorePackagePrefix從包名稱的開頭開始指定消除的部分。
          addIgnoreClassSuffix類名稱的最末尾開始指定消除的部分。默認地將Impl和Bean注冊。
          addReplaceRule根據正則表達式追加替換規則。第一個參數為正則表達式。第二個參數是替換的新字符串。
          clearReplaceRule將setCustomizedName、 addIgnorePackagePrefix、 addIgnoreClassSuffix、 addReplaceRule注冊的替換規則清除。默認注冊的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的自動注冊

          根據組件的自動注冊規則,組件的注冊可以做到自動化。進一步,AOP的注冊也可以做到自動化,這就是AOP的自動注冊機能。

          和組件的自動注冊功能組和使用的場合下,必須在組件的自動注冊設定之后,作AOP的自動注冊的設定。對于適用于使用AOP的組件的記述,必須在AOP的自動注冊設定之后進行。

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

          通過指定類名的模式來進行AOP的自動注冊的組件。

          屬性說明
          interceptor指定interceptor。想要指定復數個interceptor的場合下,請使用InterceptorChain
          pointcut適于使用interceptor的方法用逗號分隔開進行指定。不指定pointcut的情況下,實裝組件的interface的所有方法都做為interceptor的對象。對于方法名稱也可以使用正則表達式(JDK1.4のregex)來指定。

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

          <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

          針對某個interface的實裝類進行AOP的自動注冊的組件。

          屬性說明
          interceptor指定interceptor。想要指定復數個interceptor的場合下,請使用InterceptorChain
          targetInterface針對某一指定的interface的實裝組件,使用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的自動注冊

          META信息也可以自動注冊。

          同組件的自動注冊相組合使用的場合下,必須在組件的自動注冊設定之后,做META的自動注冊的設定記述。 調用META信息的組件必須在META自動注冊的設定之后記述。

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

          通過指定類名的模式來做META自動注冊的組件。
          被自動注冊的META數據,將做為在這個組件自身的定義中一個叫做autoRegister的META數據的子數據來記述。

          方法說明
          addClassPattern將想要自動注冊的類模式注冊。第一個參數是組件所在包的名字。子包也將被用回歸的方式所檢索。第二個參數是類名。可以使用正則表達式。用“,”做分隔符號,可以做復數個記述。
          addIgnoreClassPattern將不想自動注冊的類模式注冊。第一個參數是組件所在包的名字。子包也將被用回歸的方式所檢索。第二個參數是類名。可以使用正則表達式。用“,”做分隔符號,可以做復數個記述。
          <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數據自動地注冊到其它的組件定義中。

          Hotswap

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

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

          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>

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

          s2container.dicon

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

          把s2container.dicon根據class path放到根路徑下的話,就能被自動識別到。也可以使用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,有必要調用S2Container#init()。 執行了的話"Hello"表示出來后,程序就停止了,所以將GreetingImpl#greet()修改并編譯使之表示"Hello2"。這之后,請將文字終端顯示窗口調成聚焦狀態并按下ENTER鍵。雖然是用同一個instance也沒有關系,class文件被替換了的事實可以很容易的被測知。這個是實例模式為singleton的場合下的例子,實例模式為prototype的場合下,類將在調用S2Container#getComponent()的時刻被置換。

          執行結果

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

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

          S2Container標簽參考

          DOCTYPE

          DOCTYPE要在XML聲明之后指定。請象下面那樣指定。

          <?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標簽(必須)

          成為了根標簽。

          namespace屬性(任意)

          可以指定命名空間。做為Java的標識語來使用

          <?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標簽(任意)

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

          path屬性(必須)

          可以指定定義文件的路徑。相對于CLASSPATH所指定的路徑為根的絕對路徑。例如,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標簽(任意)

          定義組件。

          class屬性(任意)

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

          name屬性(任意)

          指定名稱也可以。將做為Java的標示語來使用。詳細情況請參照組件的取得

          instance屬性(任意)

          可以指定讓S2Container對組件的實例如進行管理。可以指定singleton(默認)、prototype、outer、request、session幾種類型。更詳細的請參照實例管理

          autoBinding屬性(任意)

          S2Container可以指定如何解決組件之間的依存關系。有auto(默認)、constructor、property、none幾種類型。詳細,請參照自動綁定

          arg標簽(任意)

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

          property標簽(任意)

          做為component標簽的子標簽來使用。做為屬性變量被設定的實際值,要么在正文中使用OGNL式指定,要么在子標簽中使用component標簽指定。

          name屬性(必須)

          指定屬性變量名。

          bindingType屬性(任意)

          可以根據每一個屬性變量進行細致的自動綁定控制。must、should(默認)、may、none幾個類型可以用來指定。詳細請參照自動綁定

          meta標簽(任意)

          做為components標簽component標簽arg標簽property標簽的子標簽來使用。META數據的值,要么在正文中使用OGNL式指定,要么在子標簽中使用component標簽指定。

          name屬性(任意)

          指定META名。

          initMethod標簽(任意)

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

          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標簽(任意)

          和initMethod標簽一樣。

          aspect標簽(任意)

          將AOP組入到組件的定義中。詳細請參照S2AOP的aspect標簽的說明。

          interType標簽(任意)

          象組件中組入interType。詳請請參照S2AOP的interType標簽的說明。

          description標簽(任意)

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

          OGNL式

          在S2Container中,做為表達式語言可以利用

        1. char是象'a'一樣用'括起來。
        2. 數值就像123這樣直接記述。
        3. 倫理值就直接向true,false這樣記述。
        4. new java.util.Date(0)這樣可以用類的完整合法限定名來直接調用其構造函數。
        5. @java.lang.Math@max(1, 2)這樣可以調用static方法的直接呼出結果。
        6. @java.lang.String@class這樣可以直接調用類。
        7. hoge.toString()這樣可以參照組件的方法調用結果。本例中,前提是在某個地方已經定義了叫做hoge的組件。
        8. 詳細請參照OGNL指南

          S2Container備注碼參考

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

          為了盡可能地讓更多的人樂意方便地使用備注碼,在JDK1.4中,可以使用Tiger風格的備注碼(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標簽的替代使用方法是、Aspect備注碼。與aspect標簽不同,因為可以定義復數個定義? 想要適用于復數個intercepter的情況下?請使用

          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() {
                  ...
              }
          }
          

          常量備注碼的形式如下。想要指定復數個pointcut的情況下,請象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標簽的代替使用方法是InitMethod備注碼。 與initMethod標簽不同,OGNL式的使用和參數的設定都不可以。

          Tiger方式的備注碼如下。

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

          backport175方式的備注碼如下。

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

          常量方式的備注碼如下。想要指定復數個初始化方法的情況下,請用逗號(,)做分隔符。

          public static final String INIT_METHOD = "init";
          

          DestroyMethod備注碼

          destroyMethod標簽的替代使用方式是DestroyMethod備注碼。 與destroyMethod標簽不同,OGNL式的使用,參數的設定都不可以。

          Tiger方式的備注碼如下。

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

          backport175方式的備注碼如下。

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

          常量備注碼如下。想要指定復數個初始化方法的情況下,請用逗號(,)做分隔符。

          public static final String DESTROY_METHOD = "destroy";
          


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

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

          ps: 如果是精神勝利法,沒有必要;如果是玩笑,也不應該帶歧視性。  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2
          2008-12-08 11:56 | 拜訪
          不過,帶回家研究研究,謝謝你  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2
          2008-12-16 20:32 |
          寫的很詳細,我這兩天一直在看,期待關于seasar新的文章  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2
          2008-12-25 22:50 | ln_xk
          我的項目一直在用它。不錯的框架  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2[未登錄]
          2010-01-29 14:45 | x
          寫的很詳細。多謝。。  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2[未登錄]
          2011-12-26 11:52 | aaa
          @manu
          你有本事也搞一個,人家能自己弄出來就很牛B了  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2[未登錄]
          2012-02-27 10:27 | 小菜鳥
          嗯 很詳細  回復  更多評論
            
          # re: 小日本的開源框架 Seasar2[未登錄]
          2012-09-14 14:26 | zhang
          good  回復  更多評論
            
          主站蜘蛛池模板: 壤塘县| 泾源县| 红原县| 桂东县| 阜阳市| 丰城市| 凤庆县| 定兴县| 天津市| 晋州市| 云浮市| 柘城县| 德兴市| 达拉特旗| 黔东| 双牌县| 普陀区| 称多县| 金堂县| 柘荣县| 台中县| 正阳县| 高邑县| 天台县| 大关县| 玉门市| 义乌市| 罗江县| 巴青县| 娱乐| 南平市| 桃江县| 炉霍县| 禄丰县| 泊头市| 南汇区| 星座| 南宫市| 岐山县| 渝中区| 大埔区|