Seasarは、eXtreme Programingの開発手法を使って開発されたアプリケーションサーバで、
シンプルなこと、徹底的にテストされていることが特徴です。
Webの機能は、Jettyを使っています。
データベースとして、HSQLDBも組み込まれているので、ダウンロードしてすぐに
様々な機能を試してみることができます。
また、シーサープラグインによって、Eclipseで快適に開発することもできます。
JDK1.4とEclipse2.1.1以上が必要です。
ダウンロードしたseasarsetupXXX.jarを適当なディレクトリにコピーして、
jar xf seasarsetupXXX.jarで解凍します。
seasarというディレクトリができるので、今後このディレクトリを$SEASAR_HOMEと
呼ぶことにします。
バージョン1.3以上のantがまだインストールされていないなら
コマンドラインから実行できるようにするために、
$SEASAR_HOME/binをPATH環境変数に加えてください。
コマンドラインから、ant -versionを実行して、バージョンが表示されればOKです。
これで、Seasarのインストールはこれで終了です。
Windowsの場合、$SEASAR_HOME/bin/startSeasar.batをダブルクリックします。
Unixの場合、$SEASAR_HOME/binにcdしてから、./startSeasar.shを実行します。
INFO 2003-04-01 21:03:59,183 org.seasar.system.Seasar [ISSR0001]seasar startedのように表示されればOKです。 ブラウザから、http://localhost:8080/にアクセスし、
終了は、Windowsの場合、$SEASAR_HOME/bin/shutdownSeasar.batをダブルクリックします。
Unixの場合、$SEASAR_HOME/binにcdしてから、./shutdownSeasar.shを実行します。
$SEASAR_HOME/logs/seasar.logの最後に
INFO 2003-04-01 22:30:37,678 org.seasar.system.Seasar [ISSR0003]seasar shutdownのように表示されればOKです。
Jettyの設定は、$SEASAR_HOME/classes/jetty.xmlで行います。
通常は、何もいじる必要はありません。詳しい設定内容は、
Jettyのホームページで確認してください。
Webのアプリケーションをデプロイするには、
warファイル、あるいは、warファイルを解凍したディレクトリを
$SEASAR_HOME/webappsにコピーします。
Seasarが起動中なら、$SEASAR_HOME/bin/restartJetty.bat(Unixの場合restartJetty.sh)を実行します。
Seasarが起動していないなら、単にSeasarを再起動するだけでOKです。
現状では、Webアプリケーションのホットデプロイには対応していませんが、
Jettyの起動・終了は一瞬なので、どきどきしながらホットデプロイされるのをまつより、
手動で行ったほうが、すっきりすると思っています。
実は、Seasarの起動・停止・再起動・Jettyの再起動といった処理は、
Eclipseから簡単に行うことができます。
Seasarプラグインの設定は次のように行います。
Eclipseをインストールしたディレクトリを$ECLIPSE_HOMEと呼ぶことにします。
Seasarプラグインを既にインストール済なら、$ECLIPSE_HOME/pluginsから削除します。
$SEASAR_HOME/plugins/org.seasar.eclipse_x.x.xを$ECLIPSE_HOME/pluginsにコピーして
Eclipseを再起動します。
Eclipseのウィンドウ->設定のシーサーのシートでシーサーホームを設定します。
次にEclipseのウィンドウ->パースペクティブのカスタマイズを選び
その他のツリーを開いて、シーサーをチェックしてOKをクリックします。
シーサーがメニューに現れるので、起動・停止・再起動・Jettyの再起動と
いった処理を簡単に行うことができます。
Eclipseでシーサープロジェクトを作って開発すると、
そのまま、デプロイされたWebApplicationとして、
Jettyに認識されるので、Jettyを再起動するだけで、
ブラウザを使ったテストを行うことができます。
メニューから、ファイル->新規->プロジェクト->Java->シーサープロジェクトを選んで、
次へボタンをクリックします。
プロジェクト名をexamplesとし、終了ボタンをクリックします。
パッケージ・エクスプローラーでexamplesプロジェクトを右クリックし、
最新表示を実行した後に、プロジェクトのツリーを展開すると、
WEB-INF/src,WEB-INF/classes,WEB-INF/libが作成され、
必要なファイルが既にコピーされている事がわかります。
Javaのビルドパスも設定済みなので、面倒な設定を行うことなく
すぐに開発に取り掛かることができます。
次にexamplesプロジェクトをインポートします。
examplesプロジェクトを右クリックして、インポート->ファイルシステムを選びます。
ソースディレクトリを$SEASAR_HOME/examplesにし、左側のツリーのexamplesディレクトリを
チェックし、終了ボタンをクリックします。
これで、examplesプロジェクトが完成しました。
Seasarをまだ起動していない場合は、起動してください。
既に起動済みの場合は、Jettyを再起動します。
起動しているかどうかあやふやな場合(笑)は、Seasarを再起動します。
ブラウザから、
http://localhost:8080/examples/jsp/now.jspにアクセスします。
Tue Oct 07 19:54:26 JST 2003のようになれば、設定はうまくいってます。
WebApplicationのコンテキストパスは、後から変更することもできます。
変更は、プロジェクトを右クリックして、プロパティ->シーサーのページで行います。
シーサープロジェクトであるのチェックをはずすと、jetty.xmlからWebApplicationの
設定が削除されます。
シーサープロジェクトであるをチェックしなおすと、jetty.xmlにWebApplicationの
設定を再追加することもできます。
シーサープラグインを使えば、日本語を含んだ*.propertiesも簡単に扱えます。
これまでのように、native2asciiを実行する必要もありません。
メニューのウィンドウ->設定->ワークベンチ->ファイルの関連付けで
*.propertiesを選び、シーサープロパティエディタをデフォルトに指定します。
Eclipseから*.propertiesを作成して、日本語で入力し保存すると、
自動的にユニコードでエスケープされます。
ユニコードでエスケープされた*.propertiesを読み込んだときは、日本語で表示されます。
HSQLDBの設定は、$SEASAR_HOME/classes/seasar-config.xmlのHsqldbServiceの
プロパティを設定することで行います。
最初は特に変える必要はないでしょう。
各プロパティの意味は次のとおりです。
名前 | 説明 |
---|---|
database |
データベース名を設定します。 $SEASAR_HOME/dataにデータベース名.拡張子のファイルが作成されます。 データベースが存在していない場合、自動的に作成されます。 各ファイルの意味は、データベースの構成ファイル を参照してください。 |
port |
JDBC Driverの接続を受け付けるポートです。デフォルトは、9001になります。 |
silent |
falseの場合、HSQLDB自身の詳細なメッセージをコンソールに書き出します。 |
trace |
trueの場合、JDBCの詳細なメッセージをコンソールに書き出します。 |
compact |
trueの場合、SHUTDOWN時に、CACHED TABLEのデータを再作成して、 データベースのサイズをコンパクトにします。 CASHED TABLEの詳細は、テーブルの種別を参照してください。 |
checkpointInterval |
HSQLDBに対して、CHECKPOINTを発行する間隔を指定します。単位は秒です。 0だとCHECKPOINTは発行しません。 |
retryCount |
Seasarは、HSQLDBを非同期に開始させているため、 本当に開始したことを確かめるために 非同期開始後、1秒おきにHSQLDBにSQL文を発行しています。 エラーが起きなければ、HSQLDBが起動済みとみなして、 後続のサービスを起動し、エラーが起きたら、retryCountの間、 SQL文を再発行して起動チェックを続けます。 データ量が増えて、HSQLDBの開始が遅くなった場合には、 retryCountを増やしてください。 |
HSQLDBのデータベースは、$SEASAR_HOME/dataディレクトリに作成され、
以下のファイルで構成されます。
名前 | 説明 |
---|---|
データベース名.properties |
データベースごとの設定を行います。 各項目の意味は、データベース名.propertiesの詳細 を参照してください。 |
データベース名.script |
テーブルの定義とMEMORY TABLEのデータが書き込まれます。 通常にCREATE TABLEをするとMEMORY TABLEが作成されます。 MEMORY TABLEの詳細は、テーブルの種別を参照してください。 |
データベース名.data |
CACHED TABLEのデータが書き込まれます。 CACHED TABLEの詳細は、テーブルの種別を参照してください。 |
データベース名.backup |
1番最後にSHUTDOWN, CHECKPOINTしたときのCACHED TABLEのデータを ZIP形式で圧縮したファイルです。 |
データベースごとの設定を行います。
各プロパティの意味は以下のとおりになります。
プロパティ名 | 説明 |
---|---|
readonly |
デフォルトはfalse。 trueの場合、データベースを更新することができなくなります。 |
sql.month |
デフォルトはtrue。 trueの場合、month(Date)が1-12を返します。 falseの場合、0-11を返します。 |
sql.enforce_size |
デフォルトはfalse。 trueの場合、VARCHARやCHARACTERのデータ型の値が、 テーブルの定義にあわせて、カットされたりパディングされたりします。 falseの場合、なにもしません。 |
sql.compare_in_locale |
CHARACTER、VARCHARデータ型で、ソートするときに JREのロケールに従うかどうかを表します。 デフォルトはfalse。 trueの場合、現在のJREのロケールに従ってソートされます。 falseの場合、POSIX標準にしたがってソートされます。 CACHED TABLEを含むデータベースの場合、この値を変更すると インデックスがおかしくなります。 正しく変更するためには、Seasarを停止させた後、値を変更し HsqldbServiceのcompactプロパティをtrueにして Seasarを起動し、すぐに停止させてください。 停止させるときに、HSQLDBに対して、SHUTDOWN COMPACTを実行しているので インデックスが再作成されます。 その後、compactプロパティを元に戻して、Seasarを起動しなおします。 |
sql.strict_fk |
バージョン1.7.1以降は、設定しても無視されます。 |
sql.strong_fk |
バージョン1.7.1以降は、設定しても無視されます。 |
hsqldb.cache_scale |
CACHED TABLEのデータがメモリ内で、2^hsqldb.cache_scaleのサイズ分 キャッシュされます。 デフォルトは14で、8-16でなければいけません。 |
hsqldb.log_size |
自動CHECKPOINTに達していなくても、メモリ上のlogのサイズが 指定した値を超えると、CHECKPOINTが実行されます。 単位は、Mバイトで、デフォルトは200です。 |
hsqldb.gc_interval |
GCを強制的に実行するインターバルを指定します。 デフォルトは、0なのでGCは強制されません。 通常は0以外を設定すべきではありません。 |
HSQLDBは、一時的なテーブルと3つの永続的なテーブルをサポートしています。
一時的なテーブルは、CREATE TEMP TABLE文で作成します。
データはメモリ上に保存され、Connectionがクローズされるとデータも消えます。
永続的なテーブルは、MEMORY、CACHED、TEXTの3つがあります。
MEMORY TABLEは、CREATE TABLE文で作成します。
すべてのデータはメモリと.scriptファイルに保存されます。
起動時に、.scriptファイルが読み込まれて、メモリにテーブルの内容が
再作成されます。
CACHED TABLEは、CREATE CACHED TABLE文で作成します。
hsqldb.cache_scaleによって計算されるサイズまでは、
メモリ上にデータが保存され、それを超えると.dataファイルにデータが書き出されます。
大量のデータを扱えますが、速度は、MEMORY TABLEより遅くなります。
TEXT TABLEは、CREATE TEXT TABLE文で作成します。
詳細は、TEXT TABLEのマニュアル
を参照してください。
HSQLDBに接続するためのユーティリティとして、$SEASAR_HOME/binに
runHsqldbManagerが用意されています。
起動すると、接続のTypeを聞かれます。
HSQL Database Engine Serverを選んで、OKをクリックすると
HSQLDBに接続できます。SHUTDOWNは、実行しないでください。
データベースに接続するためには、コネクションプールの設定をする必要があります。
コネクションプールの設定は、$SEASAR_HOME/classes/connectionpool-config.xmlに対して
行います。
connectionPoolタグのdataSourceName属性で、このコネクションプールは
識別されます。
connectionPoolタグは、複数記述することができますが、
その中で、dataSourceName属性の値はユニークでなければなりません。
jndiName属性にJNDIからルックアップするときの名前を指定します。
慣例として、コネクションプールのJNDI名は、jdbc/dataSourceNameとします。
xaDataSourceClassName属性にjavax.sql.XADataSourceインターフェースを
実装したクラス名を指定します。JDBC DriverがXAに対応していない場合、
org.seasar.sql.XADataSourceImplを指定します。
XA機能をまともに実装できているJDBC Driverは少ないので、
通常は、org.seasar.sql.XADataSourceImplを指定します。
timeout属性で、コネクションをクローズしてから、
プールでキープされる時間(秒)を指定します。
指定した時間を過ぎると、コネクションは破棄されます。
poolSize属性で、同時にアクティブになれる
コネクションの数を指定します。
この数を超える要求があると、コネクションがプールに返されるまで
その要求はブロックされます。
propertyタグで、xaDataSourceClassNameで指定したクラスのインスタンスに対する
プロパティを指定します。org.seasar.sql.XADataSourceImplの場合、
driverClassName,URL,user,passwordを下記のように設定します。
下記の例は、HSQLDB、Oracle、PostgreSQLの場合です。
connectionpool-config.xmlをセーブしてください。
これで、サーバの設定は終了です。
<connectionPools> <connectionPool dataSourceName="hsqldb" jndiName="jdbc/hsqldb" xaDataSourceClassName="org.seasar.sql.XADataSourceImpl" timeout="600" poolSize="20"> <properties> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="URL" value="jdbc:hsqldb:hsql://localhost:9001"/> <property name="user" value="sa"/> <property name="password" value=""/> </properties> </connectionPool> <connectionPool dataSourceName="oracle" jndiName="jdbc/oracle" xaDataSourceClassName="org.seasar.sql.XADataSourceImpl" timeout="600" poolSize="20"> <properties> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="URL" value="jdbc:oracle:thin:@localhost:1521:testdb"/> <property name="user" value="scott"/> <property name="password" value="tiger"/> </properties> </connectionPool> <connectionPool dataSourceName="postgres" jndiName="jdbc/postgres" xaDataSourceClassName="org.seasar.sql.XADataSourceImpl" timeout="600" poolSize="20"> <properties> <property name="driverClassName" value="org.postgresql.Driver"/> <property name="URL" value="jdbc:postgresql://localhost/testdb2"/> <property name="user" value="scott"/> <property name="password" value="tiger"/> </properties> </connectionPool> </connectionPools>
データベースに接続するプログラムを動かすために$SEASAR_HOME/sqlの
スクリプトを実行します。
オラクルの場合はdemo-oracle.sql、HSQLDBの場合はdemo-hsqldb.sqlを実行します。
HSQLDBの場合は、既にデモデータが用意されているので、
実際に実行する必要はありません。
他のデータベースをお使いの方は、データベースにあわせてスクリプトを修正してください。
コネクションプールには、JNDI経由(javax.naming.InitialContext)で接続します。
どこに接続するのかは、InitialContextのコンストラクタに渡すPropertiesで
設定します。
Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.seasar.naming.NamingContextFactory"); env.put(Context.PROVIDER_URL, "localhost:1108"); InitialContext ctx = new InitialContext(env);
Context.INITIAL_CONTEXT_FACTORYに設定する値は、
アプリケーションサーバごとに異なりますが、
Seasarの場合は、org.seasar.naming.NamingContextFactoryを指定します。
Context.PROVIDER_URLでSeasarの場所を指定します。
ホスト名:ポート番号の形式です。
ポート番号は、$SEASAR_HOME/classes/seasar-config.xmlの
portプロパティの値とあわせる必要があります。デフォルトは、1108です。
<service className="org.seasar.system.RMIAdaptorService"> <properties> <property name="port" value="1108"/> </properties> </service>
InitialContextからjavax.sql.DataSourceを取得します。
lookup()の引数に指定するJNDI名は、$SEASAR_HOME/classes/connectionpool-config.xmlで
connectionPoolにつけたjndiNameになります。
後は、javax.sql.DataSource#getConnection()で、コネクションを取り出し、
JDBCの処理を行うことができます。
DataSource ds = (DataSource) ctx.lookup("jdbc/hsqldb"); Connection con = ds.getConnection();
package examples.org.seasar; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; public class ConnectionPoolExample { private static final String FACTORY = "org.seasar.naming.NamingContextFactory"; private static final String URL = "localhost:1108"; private static final String JNDI_NAME = "jdbc/hsqldb"; private static final String SQL = "SELECT ename FROM emp"; public static void main(String[] args) { try { Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY); env.put(Context.PROVIDER_URL, URL); InitialContext ctx = new InitialContext(env); DataSource ds = (DataSource) ctx.lookup(JNDI_NAME); Connection con = null; Statement stmt = null; ResultSet rs = null; try { con = ds.getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery(SQL); while (rs.next()) { System.out.println(rs.getString("ename")); } } finally { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } if (con != null) { con.close(); } } } catch (Exception ex) { ex.printStackTrace(); } } }
このプログラムを実行して下記のようなエラーになった場合は、
まだSeasarが開始されていません。
javax.naming.NamingException: java.net.ConnectException: Connection refused: connect at org.seasar.naming.NamingUtil.convertNamingException(NamingUtil.java:14) at org.seasar.naming.NamingServerWrapper.lookup(NamingServerWrapper.java:44) at org.seasar.naming.NamingContext.lookup(NamingContext.java:105) at org.seasar.naming.NamingContext.lookup(NamingContext.java:98) at javax.naming.InitialContext.lookup(InitialContext.java:347) at examples.org.seasar.ConnectionPoolExample.main(ConnectionPoolExample.java:26) Caused by: java.net.ConnectException: Connection refused: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:295) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:161) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:148) at java.net.Socket.connect(Socket.java:425) at java.net.Socket.connect(Socket.java:375) at java.net.Socket.(Socket.java:290) at java.net.Socket. (Socket.java:118) at org.seasar.system.RMIConnector.getRMIAdaptorBySocket(RMIConnector.java:74) at org.seasar.system.RMIConnector.getRMIAdaptor(RMIConnector.java:41) at org.seasar.system.MBeanProxy.invoke(MBeanProxy.java:100) at $Proxy0.lookup(Unknown Source) at org.seasar.naming.NamingServerWrapper.lookup(NamingServerWrapper.java:42) ... 4 more
Seasarを開始させた後にプログラムを実行しましょう。
下記のような結果になるはずです。
SMITH ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER
トランザクションも、JNDI経由(InitialContext)で、
javax.transaction.UserTransactionを取得して処理します。
Connectionのcommit,rollbackを使うよりも、JDBCの処理とトランザクション処理を
明確に分離できます。
トランザクションのために、複数のメソッドで、Connectionを持ちまわるような必要もなくなります。
InitialContextを取得する部分は、DataSourceの場合と同様です。
lookup()で指定するJNDI名は、java:comp/UserTransactionになります。
トランザクションは、UserTransaction#begin()で開始します。
トランザクションをコミットしたい場合は、UserTransaction#commit()を呼び出します。
トランザクションをロールバックしたい場合は、UserTransaction#rollback()を呼び出します。
package examples.org.seasar; import java.sql.Connection; import java.sql.Statement; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import javax.transaction.UserTransaction; public class TransactionExample { private static final String FACTORY = "org.seasar.naming.NamingContextFactory"; private static final String URL = "localhost:1108"; private static final String TX_JNDI_NAME = "java:comp/UserTransaction"; private static final String DS_JNDI_NAME = "jdbc/hsqldb"; private static final String SQL = "UPDATE emp SET ename='SCOTT' WHERE empno = 7788"; public static void main(String[] args) { try { Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY); env.put(Context.PROVIDER_URL, URL); InitialContext ctx = new InitialContext(env); UserTransaction tx = (UserTransaction) ctx.lookup(TX_JNDI_NAME); DataSource ds = (DataSource) ctx.lookup(DS_JNDI_NAME); Connection con = null; Statement stmt = null; tx.begin(); try { con = ds.getConnection(); stmt = con.createStatement(); int rows = stmt.executeUpdate(SQL); System.out.println("updated " + rows + " row(s)"); tx.commit(); } catch (Exception ex) { tx.rollback(); ex.printStackTrace(); } finally { if (stmt != null) { stmt.close(); } if (con != null) { con.close(); } } } catch (Exception ex) { ex.printStackTrace(); } } }
実行結果は下記のようになります。
DEBUG 2003-09-15 21:01:32,299 [main] Transaction.begin() updated 1 row(s) DEBUG 2003-09-15 21:01:32,489 [main] Transaction.commit()
Webのコンテナには、使い慣れたTomcatを使い、コネクションプールや
トランザクション機能は、Seassarを使うといったこともできます。
この場合、Seasarはサーブレットとして実行します。
そのためには、WEB-INF/web.xmlに次の記述を追加します。
<servlet> <servlet-name>seasar</servlet-name> <servlet-class>org.seasar.system.SeasarServlet</servlet-class> <load-on-startup/> </servlet>
また、WEB-INF/classes/seasar-config.xmlを次のように記述します。
<seasar> <services> <service className="org.seasar.system.JMXService"/> <service className="org.seasar.system.RMIAdaptorService"> <properties> <property name="port" value="1108"/> </properties> </service> <service className="org.seasar.naming.NamingService"/> <service className="org.seasar.transaction.TransactionService"/> <service className="org.seasar.sql.ConnectionPoolService"/> </services> </seasar>
後は、WEB-INF/classesに$SEASAR_HOME/classes/connectionpool-config.xmlをコピーして
適当に編集します。
これらの設定の雛型が、$SEASAR_HOME/tomnekoに用意されているので、
それを使ってください。
Seasarは、プラグイン型のアーキテクチャを採用していて、JNDI、JTA、コネクションプールなどの
サービスも実は、Seasarサービスとして組み込まれています。
$SEASAR_HOME/classes/seasar-config.xmlをみると現在組み込まれているサービスを
確認できます。
<seasar> <services> <service className="org.seasar.system.JMXService"/> <service className="org.seasar.system.RMIAdaptorService"> <properties> <property name="port" value="1108"/> </properties> </service> <service className="org.seasar.naming.NamingService"/> <service className="org.seasar.transaction.TransactionService"/> <service className="org.seasar.sql.ConnectionPoolService"/> <service className="org.seasar.mbean.MBeanService"/> </services> </seasar>
JMXServiceは、Seasarの中核となるサービスで、JMXの機能を提供しています。
RMIAdaptorServiceは、JMXServiceをRMI経由で利用するためのアダプタ機能を提供しています。
この例のように、プロパティに値を設定することもできます。
RMIAdaptorServiceには、getPort(),setPort()のメソッドが定義されているため、
Seasarは、portをプロパティとして認識できます。プロパティがプリミティブ型の場合、
文字列からプリミティブ型への変換は自動的に行われます。
SeasarContextの説明で
java.naming.provider.urlにlocalhost:1108を
指定していたかと思いますが、この1108はRMIAdaptorServiceのポート番号をあわせる必要があります。
NamingServiceは、JNDIの機能を提供しています。
TransactionServiceは、JTA(トランザクション)の機能を提供しています。
ConnectionPoolServiceは、コネクションプールの機能を提供しています。
MBeanServiceは、MBeanをサービスとしてSeasarに組み込む機能を提供しています。
MBeanについては、MBeanサービスで説明します。
Seasarサービスを提供するためには、org.seasar.system.Lifecycleインターフェースを
実装したクラスをseasar-config.xmlのclassNameに記述するだけなので簡単です。
上記の例のように、サービスのインスタンスのプロパティを設定することもできます。
import org.seasar.util.SeasarException; public interface Lifecycle { public void start() throws SeasarException; public void stop() throws SeasarException; }
Seasarの起動時に、seasar-config.xmlに登録されている順番で、各サービスの
start()が呼び出されます。
Seasarの終了時には、seasar-config.xmlに登録されている逆の順番で、各サービスの
stop()が呼び出されます。