前言
在上一篇介绍了spirng aop创建创建动态代理的过程,本片着重分析一下切面方法的执行过程。以JKD动态代理为例。
方法增强(责任链模式)
来到JDK的动态代理类JdkDynamicAopProxy,它是一个InvocationHandler,JKD动态代理基于InvocationHandler的invoke方法进行方法增强:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
//equals方法不需要代理
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
//hashCode方法不需要代理
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
//若执行的class对象是DecoratingProxy 则不会对其应用切面进行方法的增强。返回源目标类型
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
//如果目标对象实现的Advised接口,则不会对其应用切面进行方法的增强,直接执行方法
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
/**
* 暴露我们的代理对象到线程变量中,需要搭配@EnableAspectJAutoProxy(exposeProxy = true)一起使用.
* aop中方法都是被切入的方法,但是在切入的方法中通过
* this来调用另外一个方法的时候,那么该方法就不会被代理执行,而是通过方法内部执行
* 设置exposeProxy = true可以使上述调用也走代理
*事务方法调用事务方法的时候需要设置exposeProxy = true
*/
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//构建方法拦截器责任链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
MethodInvocation.
if (chain.isEmpty()) {
//为空则直接调用目标方法,不过一般这里不会为空,还记得在匹配方法获得的advisor集合么
//spring会额外加入一个ExposeInvocationInterceptor,这个Interceptor总能匹配成功
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//创建一个MethodInvocation对象
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//使用MethodInvocation进行责任链的调用
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
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()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
、}
首先是构建目标方法的拦截器责任链this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass):
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
//先从缓存中取
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
//缓存没有则构建拦截器链
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
//获取通知器适配器注册中心
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//拿到当前方法的通知器
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
//遍历每个Advisor,把Advisor转换成拦截器MethodInterceptor
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
//一般都为PointcutAdvisor
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
//判断该Advisor是否能够匹配当前方法
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
//如果能够匹配,获取advisor对应的MethodInterceptor
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
//Introduction就不看了
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
//如果不是PointcutAdvisor,也能处理,只要有对应的适配器的支持
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
看下如何从AdvisorAdapterRegistry中获取拦截器:
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
//如果通知就是MethodInterceptor,就不用转换了
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
//如果有存在支持的适配器,则用适配器转换成MethodInterceptor
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
关于这个通知器的适配器,看一个before通知的例子(MethodBeforeAdviceAdapter):
public boolean supportsAdvice(Advice advice) {
//支持MethodBeforeAdvice
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
//返回对应MethodBeforeAdvice的MethodInterceptor
return new MethodBeforeAdviceInterceptor(advice);
}
然后是重头戏,拦截器责任链的调用,我们的源目标方法会在拦截器的最后一个,也就是会在最后一个调用。看一下拦截器的顺序:ExposeInvocationInterceptor,AspectJAfterThrowingAdvice,AfterReturningAdviceInterceptor,AspectJAfterAdvice,AspectJAfterAdvice,AspectJAroundAdvice,MethodBeforeAdviceInterceptor。其中环绕通知和前置通知的顺序不是固定的,有兴趣的可以自己实验一下,当然,通常我们不会同时加让环绕通知和前置通知。进入方法执行,ReflectiveMethodInvocation#proceed:
public Object proceed() throws Throwable {
//如果当前拦截器为最后一个,则表示调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//调用原来对象方法
return invokeJoinpoint();
}
//获取当前拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
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 {
return proceed();
}
}
else {
//从第一个拦截器开始执行,注意把自己当作参数传入
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
首先是暴露Invocation的拦截器:
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
//设置当前MethodInvocation到本地线程变量
invocation.set(mi);
try {
//继续调用责任链
return mi.proceed();
}
finally {
//回复原来的MethodInvocation
invocation.set(oldInvocation);
}
}
在每个拦截器中会执行作为参数传入的MethodInvocation#proceed,又会回到ReflectiveMethodInvocation中,拦截器下标加一,接着执行下一个拦截器的方法,以此类推,形成责任链,接下来是异常通知:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//先继续调用责任链
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
//发生异常则执行异常通知
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
返回通知:
public Object invoke(MethodInvocation mi) throws Throwable {
//还是先调用责任链
Object retVal = mi.proceed();
//返回后执行返回通知
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
后置通知:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
//在finally中执行后置通知
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
环绕通知会特殊一点:
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
//MethodInvocation转换成ProxyMethodInvocation
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
//创建一个ProceedingJoinPoint,作为参数传入invokeAdviceMethod方法,便于在around通知方法中往后执行责任链
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
//执行环绕通知
return invokeAdviceMethod(pjp, jpm, null, null);
}
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
//绑定参数,执行环绕通知
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
//反射执行环绕通知方法,在环绕通知中,先执行环绕前置的方法,然后调用
//ProceedingJoinPoint#proceed()调用责任链的下一个方法,一般为before通知
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
在环绕通知的方法中,调用ProceedingJoinPoint#proceed会继续责任链,来到前置通知:
public Object invoke(MethodInvocation mi) throws Throwable {
//执行前置通知
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//执行责任链
return mi.proceed();
}
拦截器下标更新到最后一个后,执行目标方法,然后在环绕通知中返回,环绕通知继续向下执行,最后方法执行的顺序大概是:
- 环绕前置
- 前置通知
- 环绕后置
- 后置通知
- 返回通知
- 异常通知(有异常的话)
不过环绕前置和前置通知的顺序也不是固定的,因为在对通知器进行排序的过程中使用的是拓扑排序,有兴趣的小伙伴可以研究一下,笔者也不甚了解。
总结
spring aop利用切面这个概念实现对目标方法的增强,使用了责任链模式对目标对象的方法进行拦截,至此AOP的源码差不多到这里就结束了。AOP算是整个spring的一个难点了吧,其实spring的声明式事务也是通过AOP实现的,不过并没有用切面的形式,而是直接向容器注册Adsivor,省去了切面的解析。