12

元の質問の概要: AOPプロキシで標準のSpring Transactionsを使用すると、同じクラスの@Transactional-markedメソッドから@Transactional-markedメソッドを呼び出して、トランザクション内に含めることはできません(特に前述の理由により)プロキシー)。これはおそらくAspectJモードのSpringTransactionsで可能ですが、どのように実行されますか?

編集:ロードタイムウィービングを使用したAspectJモードでのSpringトランザクションの完全な要約:

以下を追加しますMETA-INF/spring/applicationContext.xml

<tx:annotation-driven mode="aspectj" />

<context:load-time-weaver />

AnnotationSessionFactoryBean(アプリケーションコンテキストですでにとがHibernateTransactionManager設定されていると仮定transaction-manager="transactionManager"します。タグに属性として追加でき<tx:annotation-driven />ますが、トランザクションマネージャーBeanのid属性の値が実際に " "の場合、" "transactionManagerとして冗長になります。transactionManagerその属性のデフォルト値です。)

追加しMETA-INF/aop.xmlます。内容は以下の通りです。

<aspectj>
  <aspects>
    <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect" />
  </aspects>
  <weaver>
    <include within="my.package..*" /><!--Whatever your package space is.-->
  </weaver>
</aspectj>

に追加aspectjweaver-1.7.0.jarspring-aspects-3.1.2.RELEASE.jarますclasspath。私はビルドツールとしてMavenを使用しているので<dependency />、プロジェクトのPOM.xmlファイルの宣言は次のとおりです。

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.7.0</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>

spring-instrument-3.1.2.RELEASE.jarとしては必要ありませんが、次のよう<dependency />に、 JVMフラグでポイントできるようにどこかclasspathに必要です。-javaagent

-javaagent:full\path\of\spring-instrument-3.1.2.RELEASE.jar

私はEclipseJunoで作業しているので、これを設定するには、「ウィンドウ」->「設定」->「Java」->「インストールされたJRE」に移動しました。次に、リストボックスでチェックされているJREをクリックし、リストボックスの右側にある[編集...]ボタンをクリックしました。表示されるポップアップウィンドウの3番目のテキストボックスには、「デフォルトのVM引数:」​​というラベルが付いています。これは、-javaagentフラグを入力するか、コピーして貼り付ける必要がある場所です。

次に、実際のテストコードクラスについて説明します。まず、私のメインクラス、TestMain.java

package my.package;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain {
  public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml");
    TestClass testClass = applicationContext.getBean(TestClass.class);
    testClass.nonTransactionalMethod();
  }
}

そして、私のトランザクションクラス、TestClass.java

package my.package;

import my.package.TestDao;
import my.package.TestObject;
import org.springframework.transaction.annotation.Transactional;

public void TestClass {
  private TestDao testDao;

  public void setTestDao(TestDao testDao) {
    this.testDao = testDao;
  }

  public TestDao getTestDao() {
    return testDao;
  }

  public void nonTransactionalMethod() {
    transactionalMethod();
  }

  @Transactional
  private void transactionalMethod() {
    TestObject testObject = new TestObject();
    testObject.setId(1L);
    testDao.save(testObject);
  }
}

ここでの秘訣は、がの場合、そのクラスTestClassのフィールドは、アプリケーションコンテキストがロードされる前にロードされるということです。ウィービングはクラスのロード時に行われ、このウィービングはアプリケーションコンテキストを介してSpringによって行われるため、アプリケーションコンテキストがロードされて認識される前にクラスが既にロードされているため、ウィービングされません。TestMainClassLoader

TestObjectとの詳細TestDaoは重要ではありません。それらがJPAおよびHibernateアノテーションと接続されており、永続性のためにHibernateを使用し(それらがそうであるため)、すべての必要な<bean />ものがアプリケーションコンテキストファイルに設定されていると仮定します。

編集:コンパイル時ウィービングを使用したAspectJモードでのSpringトランザクションの完全な要約:

以下を追加しますMETA-INF/spring/applicationContext.xml

<tx:annotation-driven mode="aspectj" />

AnnotationSessionFactoryBean(アプリケーションコンテキストですでにとがHibernateTransactionManager設定されていると仮定transaction-manager="transactionManager"します。タグに属性として追加でき<tx:annotation-driven />ますが、トランザクションマネージャーBeanのid属性の値が実際に " "の場合、" "transactionManagerとして冗長になります。transactionManagerその属性のデフォルト値です。)

に追加spring-aspects-3.1.2.RELEASE.jaraspectjrt-1.7.0.jarますclasspath。ビルドツールとしてMavenを使用しているので、ファイルの<dependency />宣言は次のとおりです。POM.xml

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.7.0</version>
</dependency>

Eclipse Junoの場合:ヘルプ-> Eclipseマーケットプレイス->「検索:」というラベルの付いたテキストボックス->「ajdt」と入力->[Enter]を押します->「AspectJ開発ツール(Juno)」->インストール->その他

Eclipseを再起動した後(作成されます)、プロジェクトを右クリックしてコンテキストメニューを表示します。下部の近くを見てください:[設定]->[AspectJプロジェクトに変換]。

<plugin />次の宣言をPOM.xml(再びMavenで!)に追加します。

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>aspectj-maven-plugin</artifactId>
  <version>1.4</version>
  <configuration>
    <aspectLibraries>
      <aspectLibrary>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
      </aspectLibrary>
    </aspectLibraries>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
        <goal>test-compile</goal>
      </goals>
    </execution>
  </executions>
</plugin>

別の方法:プロジェクトを右クリックして、コンテキストメニューを表示します。下部を見てください:AspectJツール->AspectJビルドパスの設定->アスペクトパスタブ->「外部JARの追加...」を押します->検索full/path/of/spring-aspects-3.1.2.RELEASE.jar->「開く」を押します->「OK」を押します。

Mavenルートを使用した場合、<plugin />上記はおかしくなります。これを修正するには:[ヘルプ]->[新しいソフトウェアのインストール...]->[追加...]を押します->[名前:]というラベルの付いたテキストボックスに好きなものを入力します->[名前]というラベルの付いたテキストボックスに入力またはコピーhttp://dist.springsource.org/release/AJDT/configurator/して貼り付けます場所:"->[OK]を押します->少し待ちます->[Maven Integration for EclipseAJDTIntegration]の横にある親チェックボックスをオンにします->[次へ>]を押します->[インストール]->[その他]

プラグインがインストールされ、Eclipseを再起動すると、POM.xmlファイル内のエラーは解消されているはずです。そうでない場合は、プロジェクトを右クリックしてコンテキストメニューを表示します。Maven->プロジェクトの更新->[OK]を押します。

次に、実際のテストコードクラスについて説明します。今回は1つだけ、TestClass.java

package my.package;

import my.package.TestDao;
import my.package.TestObject;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

public void TestClass {
  private TestDao testDao;

  public void setTestDao(TestDao testDao) {
    this.testDao = testDao;
  }

  public TestDao getTestDao() {
    return testDao;
  }

  public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml");
    TestClass testClass = applicationContext.getBean(TestClass.class);
    testClass.nonTransactionalMethod();
  }

  public void nonTransactionalMethod() {
    transactionalMethod();
  }

  @Transactional
  private void transactionalMethod() {
    TestObject testObject = new TestObject();
    testObject.setId(1L);
    testDao.save(testObject);
  }
}

これにはトリックはありません。ウィービングは、クラスのロードとアプリケーションコンテキストのロードの両方の前であるコンパイル時に行われるため、これら2つの順序は重要ではなくなります。これは、すべてが同じクラスに入ることができることを意味します。Eclipseでは、[保存]をクリックするたびにコードが常に再コンパイルされるため(「ワークスペースの構築:(XX%)」と表示されているときにコードが何をしているのか疑問に思ったことはありませんか?)、いつでもコードを作成してすぐに使用できます。

Load-Timeの例と同じように、TestObjectとの詳細TestDaoは重要ではありません。それらがJPAおよびHibernateアノテーションと接続されており、永続性のためにHibernateを使用し(それらがそうであるため)、すべての必要な<bean />ものがアプリケーションコンテキストファイルに設定されていると仮定します。

4

1 に答える 1

9

あなたの質問を読むことによって、あなたがどこで立ち往生しているのかは本当に明確ではないので、AspectJにあなたの@Transactionalメソッドをインターセプトさせるために必要なものを簡単にリストします。

  1. <tx:annotation-driven mode="aspectj"/>Spring構成ファイル内。
  2. <context:load-time-weaver/>Spring構成ファイルにもあります。
  3. クラスパスのMETA-INFフォルダーに直接あるaop.xml。この形式についてもここで説明します。@Transactionalアノテーションを処理するアスペクト定義が含まれている必要があります 。<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
  4. 同じファイル内のweaver要素には、どのクラスをウィーブするかを指示するinclude句も含まれている必要があります。<include within="foo.*"/>
  5. aspectjrt.jar、、aspectjweaver.jarおよびクラスパスspring-aspects.jarspring-aop.jar
  6. フラグ-javaagent:/path/to/spring-instrument.jar(または以前のリリースで呼び出されていたSpring-agent)を使用してアプリケーションを起動する

最終ステップは必要ないかもしれません。これは、の使用を可能にする非常に単純なクラスですが、使用InstrumentationLoadTimeWeaverできない場合、Springは別のロード時間ウィーバーを使用しようとします。しかし、私はそれを試したことがありません。

ここで、すべての手順を実行しても問題が解決しない場合は、ウィーバー(aop.xmlで定義)でいくつかのオプションを有効にすることをお勧めします。

<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">

これにより、ウィーバーはウィービングされている情報の束を出力します。クラスが織り込まれているのを見たら、そこであなたを探すことができますTestClass。そうすれば、少なくともトラブルシューティングを続行するための開始点があります。


2番目の編集については、「クラスが実行を試みる前に織りが十分に速く行われていないようです。」、答えは「はい」です。これは発生する可能性があります。私は以前にこのような状況を経験しました

私は詳細について少しさびていますが、基本的には、アプリケーションコンテキストが作成される前にロードされるクラスをSpringが織り込むことができないということです。アプリケーションコンテキストをどのように作成していますか?プログラムで実行していて、そのクラスがを直接参照している場合は、ロードが早すぎるTestClassため、この問題が発生する可能性があります。TestClass

残念ながら、AspectJのデバッグは地獄であることがわかりました。

于 2012-07-26T18:48:34.157 に答える