我需要编写一个方面(让我们称之为A),该方面在运行时显示所有已执行的切入点。有没有办法编写像call(...)这样的切入点,而无需使用方面的名称直接指向另一个切入点?
我写的东西大都使用了对泛型函数和inside()的调用,这样当一个方面中的函数被调用时,我的方面A会打印出一些东西。我觉得这不是一个理想的解决方案,因为我总是需要写所有方面的名称,而且会涉及很多方面。
public class Main {
public static void main(String[] args) {
ClassA a = new ClassA();
a.methodA();
a.methodA();
a.methodB();
a.methodA();
}
}
public class ClassA {
public void methodA() {
System.out.println("MethodA");
}
public void methodB() {
System.out.println("MethodB");
}
public void methodC() {
System.out.println("MethodC");
}
}
public aspect MethodAAspect {
pointcut MethA():
call(public * ClassA.methodA());
pointcut MethC():
call(public * ClassA.methodC());
after():
MethA() {
System.out.println("Aspect here, methodA ended.");
}
after():
MethC() {
System.out.println("Aspect here, methodC ended.");
}
}
如果在此示例中,我需要一个方面来计算所有切入点已经执行了多少次,或者在执行切入点时打印出一些内容,我应该如何编写?
答案 0 :(得分:2)
由于您的描述有些不准确,因此我不确定我是否正确理解您要实现的目标。例如,切入点不是“执行”的,方面的应用方法或建议是“执行”的。因此,我不确定您是否只想记录每个方法调用(或者可能是方法执行,请参见下面的区别),或者是否需要某种元方面来计算方面建议被执行了多少次。我在这里假设是前一种情况,因为这对我来说最有意义。
您的应用程序代码,但具有程序包名称:
package de.scrum_master.app;
public class ClassA {
public void methodA() {
System.out.println("MethodA");
}
public void methodB() {
System.out.println("MethodB");
}
public void methodC() {
System.out.println("MethodC");
}
}
package de.scrum_master.app;
public class Main {
public static void main(String[] args) {
ClassA a = new ClassA();
a.methodA();
a.methodA();
a.methodB();
a.methodA();
}
}
<强>方面拦截方法执行:强>
这方面拦截所有方法执行在自己的代码(不来电!)。
package de.scrum_master.aspect;
public aspect MyAspect {
after() : execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
日志输出为:
MethodA
execution(void de.scrum_master.app.ClassA.methodA())
MethodA
execution(void de.scrum_master.app.ClassA.methodA())
MethodB
execution(void de.scrum_master.app.ClassA.methodB())
MethodA
execution(void de.scrum_master.app.ClassA.methodA())
execution(void de.scrum_master.app.Main.main(String[]))
请注意,同样的Main.main(..)
正在记录,即使该方法从未明确地称为(但仍然执行!)。执行
<强>方面拦截方法执行:强>
此方面会拦截您自己代码中的所有方法调用,其中还包括对第三方或JDK类的调用。
请注意,为了避免无限循环,我们必须添加&& !within(MyAspect)
,因为纵横建议也调用一个方法JDK
package de.scrum_master.aspect;
public aspect MyAspect {
after() : call(* *(..)) && !within(MyAspect) {
System.out.println(thisJoinPoint);
}
}
在这种情况下,日志输出为:
MethodA
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodA())
MethodA
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodA())
MethodB
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodB())
MethodA
call(void java.io.PrintStream.println(String))
call(void de.scrum_master.app.ClassA.methodA())
当然你也可以使用call()
和限制呼叫自己的软件包,例如:
package de.scrum_master.aspect;
public aspect MyAspect {
after() : call(* de.scrum_master.app..*(..)) && !within(MyAspect) {
System.out.println(thisJoinPoint);
}
}
这里的日志输出是:
MethodA
call(void de.scrum_master.app.ClassA.methodA())
MethodA
call(void de.scrum_master.app.ClassA.methodA())
MethodB
call(void de.scrum_master.app.ClassA.methodB())
MethodA
call(void de.scrum_master.app.ClassA.methodA())
这始终取决于您要实现的目标。
如果这不是您想要的,请更精确地更新您的问题,并在评论中通知我。然后我知道我能做什么。
有关元方面的后续问题的更新:
package de.scrum_master.aspect;
public aspect MetaAspect {
before() : adviceexecution() && !within(MetaAspect) {
System.out.println(thisJoinPoint);
}
}
使用MyAspect
登录到第一个execution()
版本,更改为:
MethodA
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodA())
MethodA
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodA())
MethodB
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodB())
MethodA
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.ClassA.methodA())
adviceexecution(void de.scrum_master.aspect.MyAspect.after(JoinPoint))
execution(void de.scrum_master.app.Main.main(String[]))