Spring 如何在没有接口的情况下配置AspectJ和加载时编织
在我的项目中,我目前在编译时使用AspectJ(由于某些限制,不仅仅是SpringAOP)进行编织。为了加快Eclipse上的开发速度,我想在加载时进行编织。我成功地做到了这一点,但有一个主要的限制:为我的服务使用包含一些事务方法的接口如果我在caller类中声明服务及其实现而不是接口,则没有编织,因此不支持事务。 因此如果AspectJ支持它,那么如何配置AspectJ,使其具有无接口的加载时编织功能? 我创建了一个复制该问题的小项目: 以下测试失败 以下测试在以下情况下成功:Spring 如何在没有接口的情况下配置AspectJ和加载时编织,spring,aop,aspectj,spring-transactions,load-time-weaving,Spring,Aop,Aspectj,Spring Transactions,Load Time Weaving,在我的项目中,我目前在编译时使用AspectJ(由于某些限制,不仅仅是SpringAOP)进行编织。为了加快Eclipse上的开发速度,我想在加载时进行编织。我成功地做到了这一点,但有一个主要的限制:为我的服务使用包含一些事务方法的接口如果我在caller类中声明服务及其实现而不是接口,则没有编织,因此不支持事务。 因此如果AspectJ支持它,那么如何配置AspectJ,使其具有无接口的加载时编织功能? 我创建了一个复制该问题的小项目: 以下测试失败 以下测试在以下情况下成功: 注入的服务是
- 注入的服务是用接口声明的,而不是它的实现(即用“@Inject MyService service”替换“@Inject MyService impl service”),测试成功
- 编织是在编译过程中执行的(在本例中,配置POM和Spring应用程序上下文明显不同)。但我的目标是在加载时进行编织,以避免每次保存Java文件时出现编织阶段
- SpringAOP(tx:annotation-driven-mode=“proxy”)是一种基于代理的解决方案,用于替代AspectJ。但在本例中,我们遇到了自调用问题,即目标对象内的方法调用目标对象的其他方法,即使调用的方法标记为@Transactional,也不会在运行时导致实际事务
package mycompany.aspectj_ltw;
import static junit.framework.Assert.assertTrue;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/META-INF/spring/applicationContext.xml" })
public class MyServiceImplTest {
@Inject
MyServiceImpl service;
@Test
public void shouldBeExecutedInTransaction() {
assertTrue(this.service.isExecutedInTransaction());
}
}
aspectj ltw/src/main/java/mycompany/aspectj_ltw/MyService.java
package mycompany.aspectj_ltw;
public interface MyService {
boolean isExecutedInTransaction();
}
aspectj ltw/src/main/java/mycompany/aspectj_ltw/myserviceinpl.java
package mycompany.aspectj_ltw;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Service
public class MyServiceImpl implements MyService {
@Transactional
public boolean isExecutedInTransaction() {
return TransactionSynchronizationManager.isActualTransactionActive();
}
}
aspectj ltw/src/test/resources/META-INF/applicationContext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:component-scan base-package="mycompany.aspectj_ltw" />
<context:load-time-weaver aspectj-weaving="on" />
<aop:config proxy-target-class="true"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" proxy-target-class="true" />
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" id="dataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:mydb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
如果我没有弄错的话,这里的问题不是因为AspectJ,而是因为JUnit用例中的工作方式。在运行测试时,首先加载
MyServiceImplTest
类,然后创建Spring上下文(您需要测试类的注释来获取适当的运行程序和配置位置),因此在使用任何Spring AOP机制之前。这是,至少,我在几个月前面对同样情况时提出的解释。。。由于javaagent从JVM启动时就在那里,因此必须完全阅读/理解weaver的代码,才能准确地解释它在这里失败的原因(我没有:p)
因此无论如何,MyServiceImplTest
类型及其加载的所有成员类型(也适用于方法签名中的类型)都无法编织
要解决此问题,请执行以下操作:
- 或者避免在测试类成员和方法签名中使用编织类型(例如,像您那样使用接口)
- 或者将AspectJ weaver添加到JavaAgent中(除了spring instrument 1);如果我没记错的话,Spring应该能够使其基于AOP的机制正常工作: -javaagent:/maven-2_local_repo/org/aspectj/aspectjweaver/1.7.0/aspectjweaver-1.7.0.jar-javaagent:/maven-2_local_repo/org/springframework/spring instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
注:在您的
META-INF/aop.xml
中,可能需要添加-Xreweavable
weaver选项。首先,如果您使用的是maven,请设置pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7</version>
</dependency>
org.springframework
弹簧乐器
3.1.2.1发布
org.aspectj
aspectjweaver
1.7
然后必须使用aspectj编译器编译代码。
此编译器在META-INF/aop.xml中生成一个aop.xml文件
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-showWeaveInfo -debug -verbose -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
<include within="mycompany.aspectj_ltw..*"/>
</weaver>
</aspectj>
(我正在使用eclipse sts)
之后,我想运行一个Junit测试。
因此,您必须在eclipse运行配置窗口中设置VM参数:
-javaagent:${ASPECTJ_WEAVER_1.7}\aspectjweaver-1.7.0.jar-javaagent:${SPRING_INSTRUMENT}\SPRING-INSTRUMENT-3.1.2.RELEASE.jar
其中${ASPECTJ_WEAVER_1.7}${SPRING_INSTRUMENT}是一个环境变量。使用var按钮创建这些变量(位于窗口的右下角)。这些变量指向aspectjweaver-1.7.0.jar和spring-instrument-3.1.2.RELEASE.jar所在的文件夹。跟随助手做这个。这并不难。
注意前面的javaagent行中没有任何不可见的奇怪字符或类似字符。这听起来很奇怪,但我不得不重写同一行好几次,直到eclipse说这行很好
然后,您可以运行Junit测试。
首先可以看到aspectj运行时加载。稍后您将看到弹簧加载。。。之后,您的测试将运行,因为它没有任何spring问题或类似问题。
这是一个沉重的过程
我希望这些信息能对你有所帮助
问候谢谢!我认为这是对发生的事情的非常接近的解释。我不是100%确定,因为据我所知,Spring使用了2个类加载程序和2个类加载通过-一个测试类及其引用应该首先加载到第1个加载程序中,分析注释等,但随后它们被丢弃,并通过AspectJ提供的加载程序加载,该加载程序进行编织。。。从理论上讲,它应该允许织布正确地进行,但不知何故它并没有。我将尝试添加AspectJweaverJavaAgent和/或可重写选项,看看它是否修复了它!f***ng。。。。明亮的在经历了最令人沮丧的几个小时之后,在接受了你的建议之后,我刚刚深吸了一口气。作为记录,包括
aspectjweaver
以及spring工具
作为javaagent使我能够在spring引导应用程序中正确运行加载时编织,junit测试included@drewmoore我正在使用spring boot mvc应用程序,需要调用一个
-javaagent:C:/maven-2_local_repo/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7</version>
</dependency>