0

私は春とAspectJでtxに関する多くの投稿を経験しました。以下は要約です、言います、私はサービスクラスとそのインターフェースを持っています

interface TestService {
 void methodA();
 void methodB();
}

class TestServiceImpl implements TesService {

   @Transactional
   void methodA() {
      methodB();
   }

   @Transactional(propagation=Propagation.NEVER)
   void methodB(){}
}

そして私の構成

<tx:annotation-driven transaction-manager="jpaTxManager"/>

<bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"><ref bean="entityManagerFactory"/></property>
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>

<bean id="testService" class="com.motherframework.plugin.test.service.TestServiceImpl">
     <property name="testDAO" ref="testDAO"/>
</bean>

testService.methodA()あるクライアントクラスから電話をかけています。SpringのJDK動的プロキシの使用法に従って、はでのみ処理@Transactionalされ、では処理されmethodA()ません。したがって、コードは適切なトランザクションで実行され、コミットされます。AspectJモードを使用すると、オンもチェックされ、例外がスローされます。@Transactional(propagation=Propagation.NEVER)methodB()@Transactional(propagation=Propagation.NEVER)methodB()

さて、私の質問は、なぜこの制限がSpringによって課されるのかということです。春のデザインには2つの可能性があります。

  1. 公開されているのに、methodB()でアノテーションをチェックできないのはSpringの技術的な制限ですか?しかし、AspectJがそれをチェックできるのなら、なぜSpringではないのでしょうか。

  2. 意図的に、内部メソッド呼び出しのこのAOPチェックを制限しています。この種のメソッド呼び出し(ターゲットメソッドに異なるtransactionPropagationで注釈が付けられている場合)は、適切な設計方法に反していますか?

4

3 に答える 3

3

はい、それは技術的限界です。AspectJを使用しない場合、トランザクションアスペクトは、実際のBeanクラスインスタンスの周りにプロキシを返し、このプロキシを他のBeanに返す/注入することによって実装されます。したがって、を呼び出すtestService.methodA()と、(基本的に)次のことが起こります。

caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA()

プロキシは、呼び出しの周りにトランザクションの側面を適用します。プロキシは、testServiceImpl.methodA()前にトランザクションを開始し、後にコミット/ロールバックします。

this.methodB()から電話をかけるmethodA()と、次のようになります。

caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA() ---> testServiceImpl.methodB()

また、プロキシをバイパスするため、トランザクションの側面を適用することはできません。

AspectJはTestServiceImpl、さまざまなメソッド呼び出しの周りにアスペクトを適用するためにのバイトコードを変換するという点で異なります。

内部メソッド呼び出しの周りにアスペクトを適用することは適切な設計ではないとは言えません。バイトコードインストルメンテーションでのみ機能することに注意する必要があります。

于 2012-08-03T07:06:53.423 に答える
1

これは技術的限界です(他の人が答えているように)。Springにこれをチェックさせたい場合は、次のようにサービスを変更できます。

class TestServiceImpl implements TesService {

   TesService thiz; // setter left outside, assumed to be injected by Spring

   @Transactional
   void methodA() {
      thiz.methodB();
   }

   @Transactional(propagation=Propagation.NEVER)
      void methodB(){}

}
于 2014-08-12T13:24:03.893 に答える
0

ここでの考え方は、最も外側のメソッドがトランザクション全体に最適なものを知っているということです。しかし、お気づきのように、コーナーケースがあります。

回避策:メソッドの実装を2番目のBeanに移動し、そのBeanをに注入しますTestServiceImpl。プロキシが注入されるため、すべてのメソッド呼び出しはアノテーションに注意を払います。

いくつかのメソッドを分割する必要があります。このような状況にある場合:

methodX() {
     ...code before...
     methodB();
     ...code after...
}

コールバックを使用できます。

methodX() {
     Callable<Void> callback = new Callable<Void>() {
         Void call() {
              realImpl.methodB();
         }
     }
     realImpl.methodX(callback);
}

そしてあなたの内側の豆で:

void methodX(Callable<Void> callback) {
     ...code before...
     callback();
     ...code after...
}
于 2012-08-03T08:21:20.147 に答える