我正在检测第三方应用程序-并定义了以下切入点

@Aspect
public class MyAspect {

    @Pointcut("execution(some.app.Application.new(..))")
    public void appCreation() {
    }

    @After("appCreation()")
    public void afterCreation() {
        MyUtil.doSomething();
    }
}


现在,问题出在MyUtil.doSomething()最终调用some.app.Application的构造函数这一事实上-这当然是我的方面随后“检测到”的原因,并且再次调用MyUtil.doSomething()并调用....您明白了。

我试图在切入点定义中放入&& !within(MyAspect),但没有帮助。在MyUtil调用堆栈更远的情况下,有什么方法可以抑制切入点的检测?

如果相关:MyUtil.doSomething()不是直接调用应用程序构造函数,而是在几次中间调用之后

最佳答案

好的,首先让我们重现您的问题:

Java类:

package de.scrum_master.app;

public class Application {
    public Application() {
        System.out.println("Creating application");
    }

    public static void main(String[] args) {
        new Application();
    }
}


package de.scrum_master.app;

public class MyUtil {
    public static void doSomething() {
        System.out.println("Doing something");
        new Application();
    }
}


引起递归的问题方面:

package de.scrum_master.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import de.scrum_master.app.MyUtil;

@Aspect
public class MyAspect {
    @Pointcut("execution(*..Application.new(..))")
    public void appCreation() {}

    @After("appCreation()")
    public void afterCreation() {
        MyUtil.doSomething();
    }
}


控制台日志:

Creating application
Doing something
Creating application
Doing something
(...)
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8$Encoder.encodeLoop(Unknown Source)
    at java.nio.charset.CharsetEncoder.encode(Unknown Source)
    at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
    at sun.nio.cs.StreamEncoder.write(Unknown Source)
    at java.io.OutputStreamWriter.write(Unknown Source)
    at java.io.BufferedWriter.flushBuffer(Unknown Source)
    at java.io.PrintStream.write(Unknown Source)
    at java.io.PrintStream.print(Unknown Source)
    at java.io.PrintStream.println(Unknown Source)
    at de.scrum_master.app.MyUtil.doSomething(MyUtil.java:5)
    at de.scrum_master.aspect.MyAspect.afterCreation(MyAspect.aj:16)
    at de.scrum_master.app.Application.<init>(Application.java:6)
    at de.scrum_master.app.MyUtil.doSomething(MyUtil.java:6)
    (...)


现在我们如何避免这个问题?如果建议已经在执行,即在当前控制流或cflow()中,我们需要避免执行建议。对于建议执行,甚至还有一个特殊的切入点adviceexecution()

改进的方面避免了无限递归:

package de.scrum_master.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import de.scrum_master.app.MyUtil;

@Aspect
public class MyAspect {
    @Pointcut("adviceexecution() && within(MyAspect)")
    public void myAdvice() {}

    @Pointcut("execution(*..Application.new(..))")
    public void appCreation() {}

    @After("appCreation() && !cflow(myAdvice())")
    public void afterCreation() {
        MyUtil.doSomething();
    }
}


更正后的控制台日志:

Creating application
Doing something
Creating application


最后一点:到目前为止,我还没有质疑您的应用程序逻辑。现在我是:如果已经创建了一个实用程序方法,那么从一个实用程序方法中创建另一个应用程序真的有意义吗?我想即使这对我来说是一个有趣的AOP练习,但真正的问题出在Java代码中,而不是AspectJ代码中。

关于java - 由于无限循环而导致AspectJ StackoverflowError,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31988226/

10-11 14:35