如何使用编译编织从项目的src目录中的测试目录强制AspectJ搜索?



实际上,这将是一个更复杂的问题。我想使用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

那么,几千个字母之后的问题在哪里呢?)问题是:

  1. 我可以得到这个结果与编译编织和不使用AspectJ类加载器吗?
  2. 由于我在实际项目中有性能限制-如何能够AspectJ在这种情况下,classLoader影响非测试环境的性能?
  3. 在加载时编织的情况下,我描述-所有类的项目将由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()切入点。

最新更新