之前说过jdk的动态代理运行时就是关注对应的InvocationHandler实现,这里就是JdkDynamicAopProxy类,运行时看invoke方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 获取所有的通知
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
// 没有通知器的情况下,method.invoke
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// invocation 包裹了调用过程,除了目标方法,还有通过AOP实现的切面方法
// 主要是这个chain,是一个拦截器链,invocation.proceed()时根据具体情况选择各种切面方式
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
蛮长的,不过大部分代码都不是重点。前面就是做一些判断,对于equals、hashCode这样的方法做了通用处理,不需要代理的方法直接method.invoke.
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 这一行,拿到的通知器集合就有一部分映射成了拦截器
// We need to create a method invocation...
// invocation 包裹了调用过程,除了目标方法,还有通过AOP实现的切面方法
// 主要是这个chain,invocation.proceed()时根据具体情况选择各种切面方式
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
这部分是重点
先构造一个invocation运行时对象,里面带入了chain,然后执行proceed方法。
@Override
@Nullable
public Object proceed() throws Throwable {
// 循环执行,直到执行完
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//获得通知方法
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
//执行
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
第一部分,当链调用到最后的时候执行invokeJoinpoint(),这里就是原始的method.invoke
获得advisor是通过index获取,每次获取完index都会++, 下面的advisor.invoke(this)会传当前对象进去。 也就是说每个advisor里面只要调用了proceed方法就都会回来这里。 实际上就是这么做的。 这样就形成了一个链式调用。
下面详细看一下每个advisor里的实现。 mi.proceed 在最内层就可以理解为调用原方法
- MethodBeforeAdviceInterceptor
// 调用方法前通知方法,在调用方法。 before方法实际上还是aspectJAdviceMethod的invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
先调通知方法,再proceed继续往下走
- AspectJAfterAdvice
// 就是包了层finally, 里面还是aspectJAdviceMethod.invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
包了层finally,里面是通知方法,就是说最后不管怎么样都会来执行一下这个通知方法
- AfterReturningAdviceInterceptor
//返回后加了方法,内部就是调用invokeAdviceMethod,最终还是aspectJAdviceMethod的invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
先执行原方法,然后加入后置通知方法。当然前面如果异常了就没这个了。
- AspectJAfterThrowingAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 就是外面包了一层异常捕获,捕获到异常执行invokeAdviceMethod
// 里面就是aspectJAdviceMethod的invoke调用
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
就是包了层异常捕获,在获取异常后执行通知方法。当然没异常就不会进去了
- AspectJAroundAdvice
/这个会先把MethodInvocation封装成ProceedingJoinPoint,然后在调用的时候当做参数传进去。
// mi.process是调用用户的方法,这里把mi包进去,然后调用通知方法,当通知方法里调用pjp.process时就是调用了mi的
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}
这里包装了一下参数,然后执行通知方法,这也是为什么我们定义的通知方法参数中需要ProceedingJoinPoint参数的原因。 而调用joinPoint.proceed()时,实际上就是上面的mi.proceed(), 就又回到了链中。
至此jdk动态代理运行时完了。 cglib的实现和这个差不多,最终每个advisor调用也是上面这部分代码。
总结一下
- 5种通知器,对应5种处理方法。
- 顺序,注意顺序。
- 原方法调用时是method.invoke,即原方法的反射调用,当方法中调用其他方法时,是不进入AOP切面的。