- - PR -
SpringとStrutsの連携時のスレッドセーフの扱い
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2006-10-02 18:57
質問です。
以下の場合、スレッドセーフになりますか? ・SpringとStrutsの連携で「DelegatingActionProxy」を使用 ・Service層のオブジェクトをSetterインジェクションしてインスタンス変数に保持 ※Service層のオブジェクトはスレッドセーフを意識していない StrutsはスレッドセーフにするにはActionでインスタンス変数を使用しないとなると ↑の場合、スレッドセーフにならないような気がします。 もし、スレッドセーフにならないとして、ActionSupportを使用する、synchronizedする 以外でいい方法があれば教えてください。 | ||||
|
投稿日時: 2006-10-02 22:54
背景がつかみにくいのですが、スレッドセーフにならないと思う理由は何でしょう?
ActionといっているのはHTTPリクエストの実処理を書くクラスのことですよね? 確かに、一般的にServletはリクエスト単位でスレッドが立ち上がるので その都度インスタンスを生成するセッティングにでもしない限りは インスタンス変数を用いるとスレッドセーフとならないことが多いですね。 ところで、インミュータブルなオブジェクト、つまり不変オブジェクトですが、 それに関して言えばsynchronizedやvolatileを設定しなくとも スレッドセーフとなりえます。 ま、読み取るだけなら別に同期はいらないわけで。 書き込みがされる場合に注意が必要となるわけですよね。 さて、DIでActionクラスになんらかの設定をするのだと思いますが、 これはコンテナの起動時に行われるはずです。 ですから、「初期化が完了したかどうか」については心配する必要はない。 それ以後にDIでインジェクションされたオブジェクトが変更されるかどうか? そのオブジェクトがフィールドを持たないステートレスなオブジェクトで 単にポリモーフィズムするためだけのオブジェクトであったら? と、まぁそんなわけですよ。 | ||||
|
投稿日時: 2006-10-03 00:45
ご回答ありがとうございます。
言葉足らずでしてすみませんでした。 nagiseさんのおっしゃるとおりActionクラスはHTTPリクエストの実処理を書くクラスのことです。 暗黙でStrutsを前提にしてしまっていたたためActionとしてしまいました。 スレッドセーフにならないと思う理由は以下の理由からです。 ・ActionにDIされているService層オブジェクトのフィールドには Domain層オブジェクト(ここではDB操作を行うDAO)がDIされている。 ・DB操作は更新処理が伴う ・DAOはiBatisのSqlMapClientDaoSupportクラスをextendsしている。 ※設定は後述 つまり、ActionのフィールドにDIされたオブジェクトはステートレスなオブジェクトでなく、書き込み処理があるということです。 そのため、インスタンス変数の扱いには注意しなければならないだろうと思い 今回、ここで質問させていただきました。 ※DAOのDI設定(参考:http://canetrash.seesaa.net/article/2068021.html) <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property> <property name="url"><value>jdbc:hsqldb:.</value></property> <property name="username"><value>postgres</value></property> <property name="password"><value>postgres</value></property> </bean> <!-- Transaction manager for a single JDBC DataSource --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"><ref local="dataSource"/></property> </bean> <!-- SqlMap setup for iBATIS Database Layer --> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"><value>sql-map-config.xml</value></property> <property name="dataSource"><ref local="dataSource"/></property> </bean> <!-- ========== DAO DEFINITIONS: IBATIS IMPLEMENTATIONS ======== --> <bean id="userDao" class="ibatis.dao.sqlmap.UserSqlMapDao"> <property name="sqlMapClient"><ref local="sqlMapClient"/></property> </bean> | ||||
|
投稿日時: 2006-10-03 08:54
う〜む。DB操作は通常はJavaの同期とは別にトランザクション管理される ものですから、そこでスレッドセーフにされているのが前提でしょう。 ですから、DBへの書き込み以外の処理でスレッドセーフではない 処理があるのだろうか?ということになります。 DB操作に当たって、DAOのクラス内で保持しているフィールドが書き換わる という事象があるのだとすればそれはステートフルだと思いますが、 通常は複数スレッドから同時に参照/更新をかけるフィールドは 保持しないものではないでしょうか。 | ||||
|
投稿日時: 2006-10-03 10:56
ご回答ありがとうございます。
>DB操作に当たって、DAOのクラス内で保持しているフィールドが書き換わる >という事象があるのだとすればそれはステートフルだと思いますが、 DAOクラス内にフィールドは作成しておらず、それを書き換えるような処理もありません。 >DB操作は通常はJavaの同期とは別にトランザクション管理される >ものですから、そこでスレッドセーフにされているのが前提でしょう。 説明が下手で回りくどい感じになってしまってすみません。 私は今回始めてStruts + Spring + iBatis を使用するのですが、ブラックボックスが多いため ↓のようなことを懸念してしまいました。 --------------------------------------------------------------------------------- 1. DAOはiBatisのSqlMapClientDaoSupportクラスをextends 2. DAOをService層のフィールドに保持し、そのService層オブジェクトはPresentation層 (Action)のフィールドに保持 → Presentation層でスレッドであるため、スレッド間で1つのService層オブジェクト (=その中のDAO)を共有 →(iBatisのソースをある程度追ったが、どのような形でjava.sql.Connectionオブジェクト を持っているか分からなかったため)Connectionオブジェクトも共有されてしまい、 スレッド間でトランザクションの不整合が発生する?? --------------------------------------------------------------------------------- しかし、nagaseさんのおっしゃるとおり、Javaの同期とは別にトランザクション管理されるものであり、 そのトランザクション管理をコンテナ(今回はSpring)に任せてしまえば、↑の懸念のような トランザクションの不整合は発生しないという理解でよろしいでしょうか? ※もちろんトランザクション属性、独立性レベルは意識する必要ありますが。 | ||||
|
投稿日時: 2006-10-03 12:37
トランザクションをきっちり管理しているにも関わらず、 Javaの同期がうまく取れないがためにスレッドセーフではないという O/Rマッピングなんて使い物になりません ![]() Connectionの取得の部分では最低限スレッドセーフにしてあるでしょうしね。 そこんとこが同期とられてなければ即刻バグ報告があがることでしょう。 個別製品の中身まではちょっと抑えていませんが、 DIで突っ込んだオブジェクトに複数スレッドで共有されるようなフィールドが ない限りは問題ないと思います。(誤りがあれば突っ込み歓迎します) このあたりDIでは「Servletではフィールドは使うな」みたいに 安直に注意勧告しにくいのが難点ですよね。 | ||||
|
投稿日時: 2006-10-03 13:03
nagiseさんの説明に「確かに、なるほど」と思わせられました。 理論的にはスレッド間でフィールドの更新がなければ問題なさそうな気がします。 あとは性能試験で負荷をかけて実感をもてる状態にしようと思います。 色々とご回答ありがとうございました。 | ||||
|
投稿日時: 2006-10-03 14:08
はじめまして。
SqlMapClientDaoSupportとは、org.springframework.orm.ibatis.support.SqlMapClientDaoSupport のことでしょうか? そうであれば、ConnectionはThreadLocalに関連付られているので、スレッドセーフとなります。 |