aspectj - 访问thisJoinPoint.getTarget()时的stackoverflower错误

时间:2014-04-19 21:18:34

标签: java aspectj

我正在尝试使用以下切入点/建议来建议大型第三方应用程序拦截所有字段访问:

before(Object target): get(* *) && target(target) && !within(aspect) {
     logger.debug("Pointcut: " + thisJoinPoint);
     logger.debug("Target: " + target);
}

对于大多数字段访问,这可以正常工作,但是对于特定访问,第二个调试行会导致StackOverflowError,并且包含该字段的方法似乎重复执行到字段访问行。 如果我删除第二个调试行,问题就会消失 - 所以似乎使用thisJoinPoint.getTarget()会导致问题。 getThis()也会出现同样的问题,但不适用于thisJoinPoint.getSourceLocation()或thisJoinPoint.getSignature()

1 个答案:

答案 0 :(得分:2)

您需要从切入点中排除通知执行或toString方法的控制流。

此示例代码会复制您的问题:

驱动程序应用程序:

主要包括自动生成的方法。 toStringhashCode

package de.scrum_master.app;

public class Application {
    private String name;

    public Application(String name) {
        super();
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Application other = (Application) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Application [name=" + name + "]";
    }

    public static void main(String[] args) {
        new Application("foo").equals(new Application("bar"));
    }
}

有失败建议的方面(StackOverflowError):

package de.scrum_master.aspect;

public aspect FieldAccessLoggingAspect {
    before(Object target): get(* *) && target(target) && !within(FieldAccessLoggingAspect) {
        System.out.println("Pointcut: " + thisJoinPoint);
        System.out.println("Target: " + target);
    }
}

有固定建议的方面:

package de.scrum_master.aspect;

public aspect FieldAccessLoggingAspect {
    before(Object target): get(* *) && target(target) && !cflow(adviceexecution()) {
        System.out.println("Pointcut: " + thisJoinPoint);
        System.out.println("Target: " + target);
    }
}

固定建议的替代方案(不太好,但也有效):

package de.scrum_master.aspect;

public aspect FieldAccessLoggingAspect {
    before(Object target): get(* *) && target(target) && !cflow(execution(public String Object+.toString())) {
        System.out.println("Pointcut: " + thisJoinPoint);
        System.out.println("Target: " + target);
    }
}

更新:以防cflow()在您的情况下无法解决问题,因为问题发生在调用堆栈的更深处,您也可以使用cflowbelow()。但只有在必要时才这样做。