Ran*_*man 11 java aop spring-aop spring-transactions
原始问题的概要:使用带有AOP代理的标准Spring事务,不可能从同一类中的非@Transactional-marked方法调用@ Transactional-marked方法并且在事务内(特别是由于前面提到的)代理).据说在AspectJ模式下使用Spring Transactions可以实现这一点,但它是如何完成的?
编辑:使用加载时编织的AspectJ模式中Spring事务的完整纲要:
将以下内容添加到META-INF/spring/applicationContext.xml:
<tx:annotation-driven mode="aspectj" />
<context:load-time-weaver />
Run Code Online (Sandbox Code Playgroud)
(我假设您已经在应用程序上下文中设置了一个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>
Run Code Online (Sandbox Code Playgroud)
添加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>
Run Code Online (Sandbox Code Playgroud)
spring-instrument-3.1.2.RELEASE.jar不需要作为<dependency />你的classpath,但你仍然需要它在某处,以便你可以用-javaagentJVM标志指向它,如下所示:
-javaagent:full\path\of\spring-instrument-3.1.2.RELEASE.jar
Run Code Online (Sandbox Code Playgroud)
我在Eclipse Juno工作,所以为了设置这个,我去了Window - > Preferences - > Java - > Installed JREs.然后我在列表框中单击选中的JRE,然后单击列表框右侧的"编辑..."按钮.生成的弹出窗口中的第三个文本框标记为"默认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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后我的交易类,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);
}
}
Run Code Online (Sandbox Code Playgroud)
这里的诀窍是,如果TestClass是TestMain类中的一个字段将在加载ClassLoader应用程序上下文之前加载.由于编织是在类的加载时,并且这种编织是由Spring通过应用程序上下文完成的,所以它不会被编织,因为在加载应用程序上下文并且知道它之前已经加载了类.
的进一步详情TestObject和TestDao不重要.假设他们使用JPA和Hibernate注释连接,并使用Hibernate进行持久化(因为他们是,他们这样做),并且所有必需<bean />的都在应用程序上下文文件中设置.
编辑:使用编译时编织在AspectJ模式下Spring事务的完整纲要:
将以下内容添加到META-INF/spring/applicationContext.xml:
<tx:annotation-driven mode="aspectj" />
Run Code Online (Sandbox Code Playgroud)
(我假设您已经在应用程序上下文中设置了一个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>
Run Code Online (Sandbox Code Playgroud)
在Eclipse Juno中:帮助 - > Eclipse Marketplace - >文本框标记为"查找:" - >键入"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>
Run Code Online (Sandbox Code Playgroud)
替代方案:右键单击项目以显示上下文菜单.看看底部附近:AspectJ工具 - >配置AspectJ构建路径 - > Aspect Path选项卡 - >按"Add External JARs ..." - >找到full/path/of/spring-aspects-3.1.2.RELEASE.jar- >按"打开" - >按"确定".
如果你采用Maven路线,<plugin />上面应该是吓坏了.为了解决这个问题:帮助- >安装新软件... - >按"添加..." - >不管你在标有"名称"文本框中喜欢的类型- >键入或复制粘贴+ http://dist.springsource.org/release/AJDT/configurator/在标文本框"位置:" - >按"确定" - >等一下 - >选中"Maven Integration for Eclipse AJDT Integration"旁边的父复选框 - >按"下一步>" - >安装 - >等等.
安装插件后,您重新启动了Eclipse,POM.xml文件中的错误应该已经消失.如果没有,请右键单击您的项目以显示上下文菜单:Maven - > Update Project - >按"OK".
现在我的实际测试代码类.这次只有一次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);
}
}
Run Code Online (Sandbox Code Playgroud)
这个没有诀窍; 由于编织发生在编译时,即在类加载和应用程序上下文加载之前,这两个事物的顺序不再重要.这意味着一切都可以进入同一个班级.在Eclipse中,每次点击Save时,你的代码都会被不断重新编译(曾经想过它在做什么时会说"建立工作空间:(XX%)"?),所以它随时都可以编织并随时可用.
就像在Load-Time示例中一样:进一步的细节TestObject并且TestDao不重要.假设他们使用JPA和Hibernate注释连接,并使用Hibernate进行持久化(因为他们是,他们这样做),并且所有必需<bean />的都在应用程序上下文文件中设置.
通过阅读你的问题,我不清楚你被困在哪里,所以我将简要列出让AspectJ拦截你的@Transactional方法所需要的东西.
<tx:annotation-driven mode="aspectj"/> 在Spring配置文件中.<context:load-time-weaver/> 以及Spring配置文件中的内容.@Transactional注释的方面定义 :<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/><include within="foo.*"/>aspectjrt.jar,aspectjweaver.jar,spring-aspects.jar并spring-aop.jar在类路径-javaagent:/path/to/spring-instrument.jar(或spring-agent,在早期版本中调用)启动应用程序最后一步可能没有必要.它是一个非常简单的类,可以使用InstrumentationLoadTimeWeaver,但如果没有可用的Spring将尝试使用另一个加载时间weaver.不过,我从未尝试过.
现在,如果您认为已经完成了所有步骤并且仍然遇到问题,我可以建议在weaver上启用一些选项(在aop.xml中定义):
<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">
Run Code Online (Sandbox Code Playgroud)
这使得织布工输出了大量正在编织的信息.如果您看到正在编织的课程,您可以在TestClass那里寻找.然后你至少有一个起点继续进行故障排除.
关于你的第二次编辑,"这几乎就像编织不会发生得足够快,无法在课程尝试执行之前编织.",答案是肯定的,这可能发生.我以前经历过这样的情况.
我对细节有点生疏,但基本上它是行中的东西,Spring将无法编织在创建应用程序上下文之前加载的类.您是如何创建应用程序上下文的?如果您以编程方式执行此类,并且该类具有直接引用TestClass,则可能会发生此问题,因为TestClass将过早加载.
不幸的是,我发现调试AspectJ是地狱.
| 归档时间: |
|
| 查看次数: |
3932 次 |
| 最近记录: |