在我的项目中,我目前在编译时使用AspectJ(由于某些限制而不仅仅是Spring AOP)。为了加速Eclipse的开发,我想在加载时进行编织。我成功地做到了这一点,但有一个主要的约束:为我的服务使用包含一些事务方法的接口。 如果我使用其实现而不是其接口声明服务,则在调用者类中,没有编织,因此不支持任何事务。
如果如果AspectJ支持,那么如何使用没有接口的加载时编织来配置AspectJ?
我创建了一个重现问题的小项目:
以下测试失败。
以下测试成功:
注入的服务是通过其接口而不是其实现来声明的(即通过“@Inject MyService service”替换“@Inject MyServiceImpl service”),测试成功。
在编译期间执行编织(在这种情况下,配置,POM和Spring应用程序上下文明显不同)。但我的目标是在加载时进行编织,以避免每次保存Java文件时都出现编织阶段。
Spring AOP(tx:annotation-driven mode =“proxy”),即基于代理的解决方案,用于代替AspectJ。但在这种情况下,我们遇到了自调用问题,即目标对象中调用目标对象的其他方法的方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务。
AspectJ的LTW / SRC /测试/ JAVA / myCompany的/ aspectj_ltw / MyServiceImplTest.java
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 /主/爪哇/ myCompany的/ aspectj_ltw / MyService.java
package mycompany.aspectj_ltw;
public interface MyService {
boolean isExecutedInTransaction();
}
AspectJ的LTW / SRC /主/爪哇/ myCompany的/ aspectj_ltw / MyServiceImpl.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 /测试/资源/ 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的LTW / SRC /测试/资源/ META-INF / 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>
AspectJ的LTW \ pom.xml的
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mycompany</groupId>
<artifactId>aspectj-ltw</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>aspectj-ltw</name>
<properties>
<spring.version>3.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.2.143</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>always</forkMode>
<argLine>
-javaagent:C:/maven-2_local_repo/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
运行测试的VM参数:
-javaagent:C:/maven-2_local_repo/org/springframework/spring-instrument/3.0.5.RELEASE/spring-instrument-3.0.5.RELEASE.jar
答案 0 :(得分:15)
如果我没有弄错的话,这里的问题不是由于AspectJ,而是在精确的JUnit用例中的工作方式。在运行测试时,首先加载MyServiceImplTest
类,然后创建Spring上下文(需要测试类'注释以获取适当的运行器和配置位置),因此在使用任何Spring AOP机制之前。也就是说,至少,当我几个月前遇到同样的情况时,我想出的解释......由于javaagent是从JVM启动开始的,因此必须完全读取/理解编织器的代码以精确解释为什么它在这里失败(我没有:p)。
所以无论如何,MyServiceImplTest
类型及其所有成员类型都加载了它 - 这也适用于方法签名中的类型 - 不能编织。
解决这个问题:
或将AspectJ weaver添加到你的javaagents(除了spring-instrument之外);有了这个,如果我没记错的话,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/弹簧仪器3.0.5.RELEASE.jar
Nota:在META-INF/aop.xml
中,可能需要添加-Xreweavable
weaver选项。
答案 1 :(得分:0)
首先,如果您使用的是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>
然后你必须使用aspectj编译器编译你的代码。 此编译器在META-INF / aop.xml
中生成aop.xml文件(我使用的是eclipse sts) 之后,我想运行Junit测试。 因此,您必须在eclipse运行配置窗口中设置VM args: -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}是一个environtment var。使用var按钮创建这些变量(位于窗口的右下角)。这些变量的目标是aspectjweaver-1.7.0.jar和spring-instrument-3.1.2.RELEASE.jar所在的文件夹。按照asistant来做这个。这并不困难。 注意以前的javaagent行没有任何看不见的奇怪字符或类似字符。这听起来很奇怪,但我不得不重写几次相同的行,直到eclipse说这条线很好。
然后,您可以运行Junit测试。 您可以看到的第一个是aspectj运行时加载。稍后你会看到弹簧加载...然后你的测试将会出现没有任何弹簧问题或类似问题。 这是一个沉重的过程。
我希望这些信息可以帮到你
此致