由于我对 AOP 的有限概念,我相信我们可以在 JoinPoint 之前和之后做一些事情,在这种情况下,但是我们怎样才能像上面那样包装实现呢?
你读过很好的Spring AOP manual吗?您会注意到的第一件事是对建议类型的解释,并且不仅有之前和之后,还有围绕建议。这就是你想要使用的。
基本上是这样的:
Java 帮助类:
package de.scrum_master.app;
public class SomeType {}
package de.scrum_master.app;
public class SomeResource implements AutoCloseable {
@Override public void close() throws Exception {}
}
接口:
package de.scrum_master.app;
public interface X {
void methodX1();
int methodX2(String s);
}
package de.scrum_master.app;
public interface Y {
void methodY1();
String methodY2(int i);
void methodY3(SomeType s);
}
接口实现+驱动应用:
我在 AspectJ 中实现了这个示例,而不是在 Spring AOP 中。因此,您看不到应用程序上下文,但您知道该怎么做,不是吗?
package de.scrum_master.app;
import org.springframework.stereotype.Component;
@Component
public class MyImpl implements X, Y {
@Override public void methodY1() { System.out.println("Y1"); methodX2("bar"); }
@Override public String methodY2(int i) { System.out.println("Y2"); return "dummy"; }
@Override public void methodY3(SomeType s) { System.out.println("Y3"); }
@Override public void methodX1() { System.out.println("X1"); methodY1(); }
@Override public int methodX2(String s) { System.out.println("X2"); return 42; }
public static void main(String[] args) {
MyImpl myImpl = new MyImpl();
myImpl.methodX1();
myImpl.methodX2("foo");
myImpl.methodY1();
myImpl.methodY2(11);
myImpl.methodY3(new SomeType());
}
}
请注意methodX1() 和methodY1() 在内部调用方法。这对于后面 Spring AOP 和 AspectJ 之间的区别很重要。
方面:
在Spring AOP中你可以省略execution(* *(..)) &&部分,我这里只是为了避免call()等其他连接点被拦截而导致日志臃肿。由于 Spring AOP 除了execution() 之外知道的不多,所以那里没有必要。切入点的... || ... 块周围的括号也可以去掉。
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import de.scrum_master.app.SomeResource;
@Component
@Aspect
public class WrapMethodsAspect {
@Around("execution(* *(..)) && (within(de.scrum_master.app.X+) || within(de.scrum_master.app.Y+))")
public Object wrapperAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println("Wrapping " + thisJoinPoint);
try (SomeResource res = new SomeResource()) {
return thisJoinPoint.proceed();
}
finally {
System.out.println("Unwrapping " + thisJoinPoint);
}
}
}
使用 AspectJ 进行控制台输出:
Wrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Unwrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
您在这里注意到两件事:
- 记录了静态
main(..) 方法的执行。 Spring AOP 不会发生这种情况。
- 记录内部方法调用。 Spring AOP 也不会发生这种情况。
使用 Spring AOP 的控制台输出:
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
在大多数情况下,Spring AOP 对于 Spring 用户来说已经足够了。但是,如果您需要更强大的方法来捕获其他类型的切入点或例如内部的嵌套方法调用,您将使用AspectJ via load-time weaving (LTW)。