实际上,这将是一个更复杂的问题。我想使用AspectJ仅在测试目的.已经发现建议使用if() JointPoint和一些静态布尔字段。另外,首先我开始使用aspect作为我的基本测试方法的内部静态类。经过一些实验,我把它换成了自己的类,但实际上并没有得到我想要的结果。我创建了一些测试项目。Maven pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <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>org.example</groupId>
<artifactId>Testing</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mockito.version>3.11.2</mockito.version>
<aspectj.version>1.9.7</aspectj.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-surefire-provider
-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<!--<configuration>
<argLine>-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar</argLine>
</configuration>-->
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>${maven.compiler.source}</complianceLevel>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
类:答:
package classes;
public class A {
private String a = "classes.A";
public String getA()
{
return a;
}
public String getFromB()
{
return new B().getB();
}
}
B:
package classes;
public class B {
private String b = "classes.B";
public String getB() {
return b;
}
}
测试类:
package aspectj;
import classes.A;
import classes.B;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class NewTest {
private static boolean useAspect = false;
public static boolean isUseAspect() {
return useAspect;
}
@BeforeEach
void init()
{
useAspect = true;
}
@Test
public void changeValue()
{
B b = new B();
System.out.println(b.getB());
}
@Test
public void changeValueInA()
{
A a = new A();
System.out.println(a.getFromB());
}
}
Aspect类
package aspectj;
import org.aspectj.lang.Aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class AspectB {
@Pointcut("if()")
public static boolean useAspect()
{
return NewTest.isUseAspect();
}
@Pointcut("call(* classes.B.getB())")
public void callTestMethod() {}
@Around("callTestMethod()")
public String myAdvice(ProceedingJoinPoint point) throws Throwable {
return "You have been hacked!";
}
}
主类:
package classes;
public class TestOutputHere {
public static void main(String[] args) {
System.out.println(new A().getFromB());
}
}
运行测试和主要方法后得到结果:
- changeValue()→你被黑了!
- changeValueInA()→类。B
- main(String[] args) ->类。B
第二个结果不要为我脚…因此,经过一些实验和删除AspectJ依赖项的测试范围,删除if() JointPoint(我们不能使用src中的测试类)并将Aspect类放在src中,我得到了结果:
- changeValue()→你被黑了!
- changeValueInA()→你被黑了!
- main(String[] args) ->你被黑了!
情欲结果不要对我太足。我真的不想在所有项目中都使用aspect。在那之后,我只是尝试使用一些加载时间编织配置maven surefire插件:
<configuration>
<argLine>
-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
</configuration>
我得到了我想要的结果:
- changeValue()→你被黑了!
- changeValueInA()→你被黑了!
- main(String[] args) ->类。B
那么,几千个字母之后的问题在哪里呢?)问题是:
- 我可以得到这个结果与编译编织和不使用AspectJ类加载器吗?
- 由于我在实际项目中有性能限制-如何能够AspectJ在这种情况下,classLoader影响非测试环境的性能?
- 在加载时编织的情况下,我描述-所有类的项目将由AspectJ重新编译?只有测试?重新编译在加载时是如何工作的?
我非常感谢你的回答!
你的代码中有几个问题:
-
每次测试前设置
useAspect = true
,测试结束后不重置为false
。这将把上下文转移到您希望方面处于非活动状态的其他测试中。你应该把它清理干净。 -
方面有一个依赖于测试类中的静态方法的
if()
切入点。在正常情况下,测试类在应用程序运行期间不可用。静态字段和它的访问方法(如果有的话)应该在方面类本身中。package aspectj; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class AspectB { private static boolean useAspect = false; public static void setUseAspect(boolean useAspect) { AspectB.useAspect = useAspect; } @Pointcut("call(* classes.B.getB()) && if()") public static boolean callTestMethod() { return useAspect; } @Around("callTestMethod()") public String myAdvice(ProceedingJoinPoint point) throws Throwable { return "You have been hacked!"; } }
package aspectj; import classes.A; import classes.B; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class NewTest { @BeforeEach void init() { AspectB.setUseAspect(true); } @AfterEach void cleanUp() { AspectB.setUseAspect(false); } @Test public void changeValue() { B b = new B(); System.out.println(b.getB()); } @Test public void changeValueInA() { A a = new A(); System.out.println(a.getFromB()); } }
-
可能,您的方面是在
src/test/java
而不是src/main/java
中定义的,这解释了为什么它只被编译成测试类而不是应用程序类。但是,如果从一个应用程序类到另一个应用程序类的方法调用应该被拦截,则后者是您所期望的。因此,您需要将方面移到主源代码中,并使aspectjrt
具有编译作用域,而不是测试作用域。
但是在假定方面只影响测试的情况下,我建议不要使用编译时编织(CTW),因为这意味着应用程序总是需要在其类路径上的AspectJ运行时(见上文),即使方面处于非活动状态。CTW只有在应用程序运行时方面也处于活动状态时才有意义。即便如此,如果加载时编织(LTW)可能不是更好的解决方案,例如,如果它是一个很少使用的调试方面,这也是有争议的。CTW是生产方面的理想选择。在这种情况下,很明显,使用Java代理的LTW是正确的方法。就像你说的,你甚至不需要丑陋的静态字段和if()
切入点。