一般情况下,比如说@around接口就只有一个参数ProceedingJoinPoint,是不会有问题的(只是侥幸),但是使用多个参数时,就会抛出异常。
如下,around方法有两个参数时,程序抛异常:
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TestOrderAspect {
@Pointcut("@annotation(testOrder)")
public void pointCut(TestOrder testOrder) {
}
@Around("pointCut(testOrder)")
public Object around(ProceedingJoinPoint point, TestOrder testOrder) throws Throwable {
Object result;
result = point.proceed();
return result;
}
}
CglibAopProxy的intercept方法中,会先获取一个拦截链,如果该链不为空,则需要创建methodInvocation
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
......
// 获取拦截链
List
创建完MethodInvocation后,会调用ReflectiveMethodInvocation.proceed(),进而会调用AspectJExpressionPointcut的matches方法,进行切点匹配
@Override
public boolean matches(Method method, Class> targetClass, Object... args) {
......
ProxyMethodInvocation pmi = null;
Object targetObject = null;
Object thisObject = null;
try {
// 尝试获取MethodInvocation,获取不到会抛异常
// ExposeInvocationInterceptor才会暴露出来MethodInvocation,所以要在链首位
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
targetObject = mi.getThis();
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
pmi = (ProxyMethodInvocation) mi;
thisObject = pmi.getProxy();
}
catch (IllegalStateException ex) {
......
}
try {
......
if (pmi != null && thisObject != null) { // there is a current invocation
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(getShadowMatch(method, method));
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false;
}
if (joinPointMatch.matches()) {
// 绑定参数信息,即绑定除ProceedingJoinPoint外的参数,非常重要!!!
bindParameters(pmi, joinPointMatch);
}
}
......
}
返回对应的MethodInvocation:但是如果没有将ExposeInvocationInterceptor加至拦截链首部,则无法暴露对应 的MethodInvocation,故而抛异常。
public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = invocation.get();
if (mi == null) {
throw new IllegalStateException(
"No MethodInvocation found: Check that an AOP invocation is in progress, and that the " +
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
}
return mi;
}
虽然会被matchesf方法捕获掉异常,但是由于pmi和thisObject为null,导致最终没有执行bindParameters绑定参数信息,所以,只要是2个及以上参数,则会报错。
在使用@Order来控制切面优先级时,最好不要直接定义该切面优先级为Ordered.HIGHEST_PRECEDENCE,导致无法暴露methodInvocation,一旦切面中定义的方法参数超过正常情况,就会报错。