在日本,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.jar | geronimo-jta_1.1_spec-1.0.jar | geronimo-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里面。
?
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的基本使用方法就被掌握了。
但是,不管怎么說書寫設(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,定義文件的做成是必要的。定義文件就像是為了組織組件而制作的設(shè)計(jì)書一樣的東西。形式為XML,后綴為dicon。
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的生成方法有兩種。
- 使用SingletonS2ContainerFactory。
- 使用S2ContainerFactory。
使用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的場合下,使用如下方法。
- 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中,組件的構(gòu)成所必要的值是用構(gòu)造函數(shù)來設(shè)定(Constructor Injection),還是用設(shè)定函數(shù)來設(shè)定(Setter Injection),或者是用初始化函數(shù)來設(shè)定(Method Injection),這樣進(jìn)行分類。Method Injection是S2Container的本源。S2Container支持以上所有類型和混合類型。
對(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ù)注入是指對(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ù)注入是指,通過任意一個(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>
所有的組件用一個(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)為是不同的組件。
在S2Container中,怎么樣對(duì)實(shí)例進(jìn)行管理,這個(gè)設(shè)定是用component標(biāo)簽的instance屬性。
instance屬性 | 說明 |
---|
singleton(default) | 不論S2Container.getComponent()被調(diào)用多少次都返回同一個(gè)實(shí)例。 |
prototype | S2Container.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>
組件間的依存關(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ā)生。 |
none | autoBinding的屬性雖然是auto、property情況下,自動(dòng)綁定也不適用。 |
不想讓組件依存于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>
到此為止,在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的名字來訪問。
根的S2Container的定義文件,按照慣例用app.dicon的名稱。通常放在WEB-INF/classes中就好了。
在組件中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的名稱。
在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>
對(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的名字來做為組件被自由訪問了。
根據(jù)自動(dòng)綁定的原理,DI的設(shè)定幾乎可以做近乎全部的自動(dòng)化。 使用備注碼就有可能進(jìn)行更加細(xì)致的設(shè)定。 更進(jìn)一步、對(duì)組件的注冊(cè)也進(jìn)行自動(dòng)化的話,就可以稱為組件的自動(dòng)注冊(cè)機(jī)能了。
是從文件系統(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è)定。 |
從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è)定。 |
將類從文件系統(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來控制組件名稱。
從類的完整合法名稱中將類的包的那部分名稱去掉,如果結(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也被清零。 |
將包的名字或者是一部分類的合法名做為組件名稱的設(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>
根據(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>
針對(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è)。
同組件的自動(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è)到其它的組件定義中。
一直以來,更改了源代碼并重新編譯之后的場合,想要測試編譯后的機(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。
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>
成為了根標(biāo)簽。
可以指定命名空間。做為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>
將被分割的S2Container的定義讀入的情況下使用。
可以指定定義文件的路徑。相對(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>
定義組件。
指定類的完整合法名。在正文中,是用了OGNL式來指定組件的場合下,class的屬性可以被省略。使用OGNL式來指定類的屬性的時(shí)候,需要進(jìn)行類型檢查。
指定名稱也可以。將做為Java的標(biāo)示語來使用。詳細(xì)情況請(qǐng)參照組件的取得。
可以指定讓S2Container對(duì)組件的實(shí)例如進(jìn)行管理。可以指定singleton(默認(rèn))、prototype、outer、request、session幾種類型。更詳細(xì)的請(qǐng)參照實(shí)例管理。
S2Container可以指定如何解決組件之間的依存關(guān)系。有auto(默認(rèn))、constructor、property、none幾種類型。詳細(xì),請(qǐng)參照自動(dòng)綁定。
做為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)簽指定。
做為component標(biāo)簽的子標(biāo)簽來使用。做為屬性變量被設(shè)定的實(shí)際值,要么在正文中使用OGNL式指定,要么在子標(biāo)簽中使用component標(biāo)簽指定。
指定屬性變量名。
可以根據(jù)每一個(gè)屬性變量進(jìn)行細(xì)致的自動(dòng)綁定控制。must、should(默認(rèn))、may、none幾個(gè)類型可以用來指定。詳細(xì)請(qǐng)參照自動(dòng)綁定。
做為components標(biāo)簽、component標(biāo)簽、arg標(biāo)簽、property標(biāo)簽的子標(biāo)簽來使用。META數(shù)據(jù)的值,要么在正文中使用OGNL式指定,要么在子標(biāo)簽中使用component標(biāo)簽指定。
指定META名。
做為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ì)象來使用。
指定方法名。
<?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>
和initMethod標(biāo)簽一樣。
將AOP組入到組件的定義中。詳細(xì)請(qǐng)參照S2AOP的aspect標(biāo)簽的說明。
象組件中組入interType。詳請(qǐng)請(qǐng)參照S2AOP的interType標(biāo)簽的說明。
做為components標(biāo)簽、component標(biāo)簽、arg標(biāo)簽、property標(biāo)簽的子標(biāo)簽可以使用description標(biāo)簽。可以自由地記述說明。
在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中,做為備注碼的實(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這樣的常量定義來完成備注碼功能的。
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";
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標(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";
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標(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標(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) 編輯 收藏 所屬分類:
Java 、
OpenSource