- PR -

SpringframeworkでHibernateのDAOをsingleton="false"

1
投稿者投稿内容
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-05-16 19:22
お世話になっております。

現在Springframeworkの宣言的トランザクション管理を利用してHibernateによる
データアクセスアプリケーションを開発しています。

SpringのBeanFactoryでDAOのProxyクラス(TransactionProxyFactoryBean)を
インスタンスする際に、singleton="false"の設定を行うと以下のエラーが発生します。

StackTrace-------------------------------------------------------------------
Caused by: org.springframework.beans.factory.support.BeanDefinitionValidationException: FactoryBean must be defined as singleton - FactoryBeans themselves are not allowed to be prototypes
StackTrace-------------------------------------------------------------------

FactoryBeanは、プロトタイプにできないようです。
解消方法があれば参考にさせてください。
よろしくお願いします。
hiro
常連さん
会議室デビュー日: 2005/03/10
投稿数: 32
投稿日時: 2005-05-17 10:04
TransactionProxyFactoryBeanをsingletonでない設定をすることにどんなメリットがあるのでしょうか?

TransactionProxyFactoryBeanで対象にしているオブジェクト(target)を
呼び出したときにインスタンスを生成したいのであればTargetSourceあたりを調べてください。
デフォルトでSingletonTargetSourceを使っているのでPrototypeTargetSourceを使うようにすると次々にインスタンスを生成してくれるはずです。
デメリットはインスタンス生成時トランザクションの作成(OPEN)・終了(close)を織り込む動作が発生し動作速度が低下します。

targetをPoolingするTargetSource(CommonsPoolTargetSource)もありますのでこちらも調べてみてください。



[ メッセージ編集済み 編集者: hiro 編集日時 2005-05-17 10:19 ]
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-05-17 10:13
現在のDAOクラスの構造が親クラスのメンバ変数にWhere句や検索結果のカーソルを保持する構造となっており、
BeanFactoryで取得したインスタンスがsingletonであるとマルチアクセス時に不整合となってしまうためです。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2005-05-17 10:18
FactoryがSingletonである設定であって、
Factoryが生成するオブジェクトはSingletonではないと思いますが。

#質問者と回答者の名前が一緒ですね…
hiro
常連さん
会議室デビュー日: 2005/03/10
投稿数: 32
投稿日時: 2005-05-17 11:30
先ほどの投稿でうそを書いてしまいました(申し訳ありません)

引用:

TransactionProxyFactoryBeanで対象にしているオブジェクト(target)を
呼び出したときにインスタンスを生成したいのであればTargetSourceあたりを調べてください。
デフォルトでSingletonTargetSourceを使っているのでPrototypeTargetSourceを使うようにすると次々にインスタンスを生成してくれるはずです。
デメリットはインスタンス生成時トランザクションの作成(OPEN)・終了(close)を織り込む動作が発生し動作速度が低下します。

targetをPoolingするTargetSource(CommonsPoolTargetSource)もありますのでこちらも調べてみてください。



ですが、TransactionProxyFactoryBeanとTargetSourceはまったく関係がなさそうです。
TransactionProxyFactoryBeanがorg.springframework.aop.framework.ProxyConfigを継承していて、org.springframework.aop.framework.AdvisedSupportからの継承ではありませんでした。よってTargetSourceとは関係がなさそうです。

調べてみると、
1.トランザクションのターゲットだったオブジェクトをorg.springframework.aop.framework.ProxyFactoryBeanで織り込む。
2.織り込む際、TargetSourceで指定する。
3.1で作ったIDをTransactionProxyFactoryBeanのtargetに指定する

コード:
	<bean id="managerTartget" class="HibernateDAOManager" singleton="false">
		<property name="security"><ref local="SecurityDAO"/></property>
	</bean>

	<bean id="poolTargetSource"
		class="org.springframework.aop.target.PrototypeTargetSource">
		<property name="targetBeanName"><value>managerTartget</value></property>
	</bean>
	
	<bean id="businessObject"
		class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="targetSource"><ref local="poolTargetSource"/></property>
	</bean>

	<!-- Transactional proxy for the Petclinic primary business object -->
	<bean id="manager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager"><ref local="transactionManager"/></property>
		<property name="target"><ref local="businessObject"/></property>
		<property name="transactionAttributes">
			<props>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="add*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>



のように設定するとトランザクションが生成するインスタンスは複数生成されるようになると思います。

もっと効率的な方法があるかも知れませんが・・・
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-05-17 13:23
書き込みありがとうございます。

ProxyFactoryBeanおよびPrototypeTargetSourceを利用することで呼び出し時のインスタンス生成には成功しました。
しかし、以下の問題が解決できません。

1.生成したDAOインスタンスからの親クラスのメンバ変数に値を設定する。
2.親クラスのメソッドでNo.1で設定した値を引用する。

singletonでのインスタンス時は、上記の動作が確認できたのですが、prototypeにて実施すると、
値が設定されておらず、NullPointerとなってしまいます。
以下サンプルソース

親クラス ######################################################################
public class ParentDAO extends HibernateDaoSupport implements ParentInterface{
private String param1 = null;

private viod setParam1(String param){
param1 = param;
}

public String getParam1(){
return param1.toString();
}
}

DAOクラス #####################################################################
public class ChildDAOImpl extends ParentDAO implements ChildDAO{
:
:
}
(ChildDAOでParentInterfaceを継承)
Sample.java ###################################################################
public class Sample{
public static void main(String[] args){
ChildDAO dao1 = BeanFactory.getBean("childDAO");
ChildDAO dao2 = BeanFactory.getBean("childDAO");
System.out.println("dao1="+dao1); // 別々のオブジェクトID
System.out.println("dao2="+dao2); // となっていた。(OK)
dao1.setParam1("AAA");
System.out.println("param1="+dao1.getParam1());// ←この時のparam1がnull
dao2.setParam1("BBB");
System.out.println("param1="+dao2.getParam1());// ←この時のparam1がnull
}
}
hiro
常連さん
会議室デビュー日: 2005/03/10
投稿数: 32
投稿日時: 2005-05-17 14:13
PrototypeTargetSourceが悪さをしているかも知れません。
色々なTargetSourceがあるので調べて試してみてください。
ThreadLocalTargetSourceなんかいいかも知れません。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2005-05-17 16:11
Springのそのあたりについては全く理解していませんが、
もしかして、ProxyなんとかクラスはDynamicProxyAPI(java.lang.reflect)が
使用されていたりしませんかね?

もしそうなら、ライブラリの方がリフレクションAPIの使用方法を間違っている
可能性が無きにしも非ずかと。
もし本当にそのあたりが怪しいなら、ソースコードを手に入れてデバッグしてみ
てもよいかもしれません。
1

スキルアップ/キャリアアップ(JOB@IT)