元の質問の概要: 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.jar
しspring-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によって行われるため、アプリケーションコンテキストがロードされて認識される前にクラスが既にロードされているため、ウィービングされません。TestMain
ClassLoader
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.jar
しaspectjrt-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 />
ものがアプリケーションコンテキストファイルに設定されていると仮定します。