2009-07-08 6 views
216

@Transactionalでメソッドに注釈を付けると、実際に何が起こっているのか知りたいですか? もちろん、私はSpringがそのメソッドをトランザクションにラップすることを知っています。Spring - @Transactional - バックグラウンドではどうなりますか?

しかし、私は、次の疑問があります。

  1. を私は春がプロキシクラスを作成することを聞いたことありますか?誰かがこれをもっと詳しくの深さで説明できますか? 実際にそのプロキシクラスには何が存在しますか?実際のクラスはどうなりますか?

注:このメカニズムは、プロキシをベースにしているため、のみ「外部」法はから入ってくるコールとどのように私はまた、その春のドキュメントを読み込むSpringの作成プロキシクラス

  • を見ることができますプロキシは傍受されます。これは、呼び出されたメソッドが@Transactionalとマークされていても、実行時に 'self-invocation'、つまりターゲットオブジェクト内の他のメソッドを呼び出すターゲットオブジェクト内のメソッドは実際のトランザクションにつながりません。

  • 出典:http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

    なぜ唯一の外部メソッドの呼び出しトランザクションの下になり、ない自己呼び出し方法?

    +1

    関連する議論はこちら:http://stackoverflow.com/questions/3120143/where-should-i-put-transactional-annotation-at-an-interface-definition-or-at-an/3120323#3120323 –

    答えて

    168

    これは大きなトピックです。 Springリファレンスのdocには、複数の章があります。私はAspect-Oriented ProgrammingTransactionsのものを読むことをお勧めします。これは、Springの宣言的トランザクションサポートがAOPを基礎として使用するためです。

    非常に高いレベルで、Springは、クラス自体またはメンバー上で@ Transactionalを宣言するクラスのプロキシを作成します。プロキシは実行時にほとんど見えません。これは、Springがプロキシされるオブジェクトのメソッド呼び出しの前後、または前後に振る舞いを注入する方法を提供します。トランザクション管理は、犯す可能性のある動作の一例にすぎません。セキュリティチェックは別のものです。そして、あなたはロギングのようなもののために自分自身を提供することもできます。したがって、@ Transactionalというメソッドに注釈を付けると、Springは注釈を付けるクラスと同じインタフェースを実装するプロキシを動的に作成します。また、クライアントがオブジェクトを呼び出すと、呼び出しが傍受され、プロキシメカニズムを介して動作が注入されます。

    EJBのトランザクションは、同様に、ちなみに動作します。

    あなたが確認したように、プロキシメカニズムは、コールが外部オブジェクトから着信する場合にのみ機能します。オブジェクト内で内部呼び出しを行うと、実際には、 "this"という参照を介して呼び出しが行われ、プロキシをバイパスします。しかし、その問題を回避する方法があります。私はthis forum postに1つのアプローチを説明しますが、私はBeanFactoryPostProcessorを使用して、実行時にプロキシのインスタンスを「自己参照」クラスに挿入します。私はこの参照を ""と呼ばれるメンバ変数に保存します。次に、スレッドのトランザクションステータスの変更を必要とする内部呼び出しを行う必要がある場合は、プロキシを介して呼び出しを行います(例:me.someMethod())。)フォーラムのポストは、より詳細に説明しています。 BeanFactoryPostProcessorのコードは、Spring 1.xのタイムフレームで書き直されたため、少し異なっていることに注意してください。しかし、うまくいけばそれはあなたにアイデアを与えます。私は、おそらく入手可能な更新版を持っています。

    +1

    >>プロキシは実行時にほとんど見えません ああ!!私はそれらを見て好奇心が強いです:)あなたの答えは非常に包括的でした。これはあなたが私を助けている2回目です。すべての助けをありがとう。 – peakit

    +9

    問題ありません。デバッガを使用すると、プロキシコードが表示されます。それはおそらく最も簡単な方法です。魔法はありません。彼らはSpringパッケージ内のクラスです。 –

    +0

    @Transactionアノテーションを持つメソッドがインターフェイスを実装している場合、春はダイナミックプロキシAPIを使用してトランザクション化と_not_ useプロキシを挿入します。 トランザクション化されたクラスには、どのような場合でもインターフェイスを実装することをお勧めします。 –

    139

    SpringがBean定義をロードし、@ Transactionalアノテーションを探すように設定されている場合、実際のBeanの周りにこれらのプロキシオブジェクトが作成されます。これらのプロキシオブジェクトは、実行時に自動生成されるクラスのインスタンスです。メソッドが呼び出されたときのこれらのプロキシオブジェクトのデフォルトの動作は、「ターゲット」Bean(つまり、Bean)で同じメソッドを呼び出すことです。

    しかし、プロキシにインターセプタを指定することもできます。存在する場合、これらのインターセプタは、ターゲットBeanのメソッドを呼び出す前にプロキシによって呼び出されます。 @Transactionalでアノテーション付けされたターゲットBeanの場合、SpringはTransactionInterceptorを作成し、それを生成されたプロキシオブジェクトに渡します。したがって、クライアントコードからメソッドを呼び出すと、プロキシオブジェクトのメソッドが呼び出されます。プロキシオブジェクトはTransactionInterceptor(トランザクションを開始します)を最初に呼び出すと、ターゲットBeanのメソッドを呼び出します。呼び出しが終了すると、TransactionInterceptorはトランザクションをコミット/ロールバックします。これはクライアントコードに対して透過的です。

    「外部メソッド」の場合、Beanが独自のメソッドの1つを呼び出した場合、そのメソッドはプロキシ経由では実行されません。春はプロキシにあなたのbeanをラップすることを忘れないでください。あなたのbeanはそれについて知りません。あなたのBeanの「外」からの呼び出しだけがプロキシを経由します。

    これは役に立ちますか?

    +20

    >あなたのBeanはプロキシにあなたのBeanをラップしていることを覚えておいてください。 **これはすべてです。どのような素晴らしい答え。助けてくれてありがとうございます。** – peakit

    +0

    プロキシとインターセプタの素晴らしい説明です。今私は、SpringがターゲットBeanへの呼び出しを傍受するプロキシオブジェクトを実装していることを理解しています。ありがとうございました! – dharag

    +5

    答えはとても素晴らしいので、私はちょうど前にupvoted私はすでにエラーメッセージが表示されるupvoteしようとしました! – Mustafa

    20

    視覚的な人として、私はプロキシパターンのシーケンス図で体重を計るのが好きです。矢印の読み方がわからない場合、私はこのような最初のものを読む:ClientProxy.method()を実行します。

    1. クライアントは、彼の視点から対象のメソッドを呼び出し、サイレント態様が定義される前場合、プロキシは、実際の方法(目標それ
    2. を実行するプロキシ
    3. によって傍受されます)後戻し
    4. 実行された後、スローされるメソッドの復帰後 が実行される任意の態様および/または方法は、その後 例外
    5. をスローした場合、プロキシ)が定義されている場合(アスペクト後に実行されます
    6. 呼び出すクライアント

    Proxy Pattern Sequence Diagram への最後のプロキシを返します(Iは、私は、その起源を述べた条件に写真を投稿することができました。

    0

    最も単純な答えは、トランザクションが開始する境界とメソッドが完了したときに境界が終了する@Transactionalを宣言する方法のいずれかでです。

    JPAコールを使用している場合、すべてのコミットはこのトランザクション境界内にあります。エンティティ1、エンティティ2、エンティティ3を保存しているとします。今度はentity3を保存している間に例外が発生すると、enitiy1とentity2が同じトランザクションになるので、entity1とentity2はentity3でロールバックされます。

    トランザクション:(entity1.save、entity2.save、entity3.save)。例外が発生すると、DBを使用するすべてのJPAトランザクションがロールバックされます。内部的にJPAトランザクションはSpringによって使用されます。

    関連する問題