spring-aop源码分析(3)完结_执行流程分析
创始人
2024-04-21 08:43:08
0

本文详细介绍Spring AOP的执行阶段流程。

Cglib代理的代理拦截逻辑在DynamicAdvisedInterceptor中,JDK代理的拦截逻辑在JdkDynamicAopProxy中,本文将从这两个类入手分析Spring AOP的执行阶段流程。

DynamicAdvisedInterceptor

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {// ...}

intercept方法核心逻辑

Cglib实现的动态代理都是通过这个类的intercept方法进行拦截的:

  • 该类在创建时需要传入一个advised对象,这个对象内部封装着所有的Advisor集
  • 将advised对象中封装的Advisor集转换成MethodInterceptor链
  • 构建一个CglibMethodInvocation并执行拦截器链

代码:

Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {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);// 1. 将Advisor集转换成MethodInterceptor链List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = methodProxy.invoke(target, argsToUse);} else {// We need to create a method invocation...// 2. 构建一个CglibMethodInvocation并执行拦截器链retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;
} finally {// 略
}
 

Advisor集

我们先debug看一下advised对象的Advisor集:

在这里插入图片描述

可以看到advisors的每个对象封装了如下通知对象:

  • before - AspectJMethodBeforeAdvice对象
  • after - AspectJAfterAdvice对象
  • afterReturn - AspectJAfterReturningAdvice对象
  • afterThrowing - AspectJAfterThrowingAdvice对象

getInterceptorsAndDynamicInterceptionAdvice方法

将advised对象的Advisor集转为MethodInterceptor集:

public List getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List cached = this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;
}// advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice
public List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class targetClass) {// This is somewhat tricky... We have to process introductions first,// but we need to preserve order in the ultimate list.AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();Advisor[] advisors = config.getAdvisors();List interceptorList = new ArrayList<>(advisors.length);Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());Boolean hasIntroductions = null;for (Advisor advisor : advisors) {// AOP执行的是这个分支,我们重点看这个分支if (advisor instanceof PointcutAdvisor) {// Add it conditionally.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);}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()) {// 执行这个分支// 使用InterceptorAndDynamicMethodMatcher类型封装表示在后续执行是仍需要进行一次匹配for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}} else {interceptorList.addAll(Arrays.asList(interceptors));}}}} else if (advisor instanceof IntroductionAdvisor) {// 略} else {// 略}}return interceptorList;
}
 

转换之后的chain集合里面每个元素都是InterceptorAndDynamicMethodMatcher对象,该对象里面封装着MethodInterceptor实现类对象:
在这里插入图片描述

在此记录一下类型转换对应关系:

通知类型Advice类型MethodInterceptor类型
beforeAspectJMethodBeforeAdviceMethodBeforeAdviceInterceptor
afterAspectJAfterAdvice
afterReturnAspectJAfterReturningAdviceAfterReturningAdviceInterceptor
afterThrowingAspectJAfterThrowingAdvice

创建CglibMethodInvocation执行拦截链

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

CglibMethodInvocation的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) {// 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);}
}

MethodInterceptor实现类

此处简单介绍几个MethodInterceptor实现类:

  • ExposeInvocationInterceptor
  • MethodBeforeAdviceInterceptor
  • AspectJAfterAdvice
  • AfterReturningAdviceInterceptor
  • AspectJAfterThrowingAdvice

ExposeInvocationInterceptor

这个拦截器没有实际用处,只是为了把MethodInvocation放到thread local上,便于在代码中获取并使用。下面是API文档:

Interceptor that exposes the current MethodInvocation as a thread-local object. We occasionally need to do this; for example, when a pointcut (e.g. an AspectJ expression pointcut) needs to know the full invocation context.

Don’t use this interceptor unless this is really necessary. Target objects should not normally know about Spring AOP, as this creates a dependency on Spring API. Target objects should be plain POJOs as far as possible.

If used, this interceptor will normally be the first in the interceptor chain.

public Object invoke(MethodInvocation mi) throws Throwable {MethodInvocation oldInvocation = invocation.get();invocation.set(mi);try {return mi.proceed();} finally {invocation.set(oldInvocation);}
}

这个类对外提供一个静态方法,用于获取当前线程上的MethodInvocation对象:

private static final ThreadLocal invocation =new NamedThreadLocal<>("Current AOP method invocation");public static MethodInvocation currentInvocation() throws IllegalStateException {MethodInvocation mi = invocation.get();if (mi == null) {throw new IllegalStateException("No MethodInvocation found");}return mi;
}

MethodBeforeAdviceInterceptor

执行before切面方法:

public Object invoke(MethodInvocation mi) throws Throwable {// 调用before切面方法,里面的代码不展开记录了this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());// 继续执行调用链// 此处就回到了CglibMethodInvocation的proceed方法// 此时currentInterceptorIndex已经指向下一个Interceptorreturn mi.proceed();
}

AspectJAfterAdvice

执行after切面方法:

public Object invoke(MethodInvocation mi) throws Throwable {try {// 先执行调用链return mi.proceed();} finally {// 在finally中调用after切面方法invokeAdviceMethod(getJoinPointMatch(), null, null);}
}

AfterReturningAdviceInterceptor

执行afterReturn切面方法:

public Object invoke(MethodInvocation mi) throws Throwable {// 先执行调用链Object retVal = mi.proceed();// 执行afterReturn切面方法this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;
}

AspectJAfterThrowingAdvice

执行afterThrow切面方法:

public Object invoke(MethodInvocation mi) throws Throwable {try {// 先执行调用链return mi.proceed();} catch (Throwable ex) {// 执行afterReturn切面方法if (shouldInvokeOnThrowing(ex)) {invokeAdviceMethod(getJoinPointMatch(), null, ex);}throw ex;}
}

模拟MethodInvocation调用链

源代码里面的MethodInvocation调用链代码不是很好理解,为了方便理解,此处写了一段类似的代码,如下:

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;/*** 模拟spring aop调用链*/
public class SpringAopAdvisorMain {/*** 模拟目标业务类*/public static class Service {public String doService() {System.out.println("Service.doService()");return "ok";
//      throw new RuntimeException("error");}}/*** 模拟AOP调用链*/public static class Invocation {// 拦截器集private final List interceptors;// 索引标识private int index = -1;// aop目标对象private final Object proxyObject;// aop目标方法private final Method proxyMethod;public Invocation(List interceptors, Object proxyObject,Method proxyMethod) {this.interceptors = interceptors;this.proxyObject = proxyObject;this.proxyMethod = proxyMethod;}/*** AOP调用链处理入口*/public Object process() throws Exception {// 当所有拦截器都入调用栈之后,调用目标业务方法if (index == interceptors.size() - 1) {return this.proxyMethod.invoke(this.proxyObject);} else {// 调用拦截器方法AdvisorInterceptor interceptor = interceptors.get(++index);return interceptor.process(this);}}}/*** 模拟AOP调用链拦截器*/interface AdvisorInterceptor {Object process(Invocation invocation) throws Exception;}/*** 纯粹是为了实验显示name值才创建了这个抽象类*/public static abstract class AbstractAdvisorInterceptor implements AdvisorInterceptor {protected String name;public AbstractAdvisorInterceptor(String name) {this.name = name;}}/*** 前置通知拦截器*/public static class BeforeAdvisorInterceptor extends AbstractAdvisorInterceptor {public BeforeAdvisorInterceptor(String name) {super(name);}@Overridepublic Object process(Invocation invocation) throws Exception {this.before();return invocation.process();}private void before() {System.out.printf(">>> %s.%s\n", name, "before");}}/*** 返回通知拦截器*/public static class AfterReturnAdvisorInterceptor extends AbstractAdvisorInterceptor {public AfterReturnAdvisorInterceptor(String name) {super(name);}@Overridepublic Object process(Invocation invocation) throws Exception {Object ret = invocation.process();this.afterReturn();return ret;}private void afterReturn() {System.out.printf(">>> %s.%s\n", name, "afterReturn");}}/*** 异常通知拦截器*/public static class AfterThrowingAdvisorInterceptor extends AbstractAdvisorInterceptor {public AfterThrowingAdvisorInterceptor(String name) {super(name);}@Overridepublic Object process(Invocation invocation) throws Exception {try {return invocation.process();} catch (Exception e) {this.afterThrowing();throw e;}}private void afterThrowing() {System.out.printf(">>> %s.%s\n", name, "afterThrowing");}}/*** 后置通知拦截器*/public static class AfterAdvisorInterceptor extends AbstractAdvisorInterceptor {public AfterAdvisorInterceptor(String name) {super(name);}@Overridepublic Object process(Invocation invocation) throws Exception {try {return invocation.process();} finally {this.after();}}private void after() {System.out.printf(">>> %s.%s\n", name, "after");}}public static void main(String[] args) throws Exception {// 创建拦截器List interceptors = new ArrayList<>();interceptors.add(new BeforeAdvisorInterceptor("before1"));interceptors.add(new AfterAdvisorInterceptor("after1"));interceptors.add(new AfterReturnAdvisorInterceptor("afterReturn1"));interceptors.add(new AfterThrowingAdvisorInterceptor("afterThrowing1"));interceptors.add(new BeforeAdvisorInterceptor("before2"));interceptors.add(new AfterAdvisorInterceptor("after2"));interceptors.add(new AfterReturnAdvisorInterceptor("afterReturn2"));interceptors.add(new AfterThrowingAdvisorInterceptor("afterThrowing2"));// 目标业务层方法Service service = new Service();Method method = Service.class.getMethod("doService");// 调用链Invocation invocation = new Invocation(interceptors, service, method);Object result = invocation.process();System.out.println("result: " + result);/** 正常输出:* >>> before1.before* >>> before2.before* Service.doService()* >>> afterReturn2.afterReturn* >>> after2.after* >>> afterReturn1.afterReturn* >>> after1.after* result: ok* *//** 异常输出:* >>> before1.before* >>> before2.before* Service.doService()* >>> afterThrowing2.afterThrowing* >>> after2.after* >>> afterThrowing1.afterThrowing* >>> after1.after* */}
}

JdkDynamicAopProxy

他是InvocationHandler的实现类,在invoke方法中实现了JDK代理的拦截逻辑。

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 {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.// 1. 将Advisor集转换成MethodInterceptor链// 和Cglib代理一样List 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.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);} else {// We need to create a method invocation...// 2. 构建一个ReflectiveMethodInvocation并执行拦截器链MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, 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("");}return retVal;} finally {// 略}
}
 

整体上和Cglib代理的拦截器逻辑一样。

后续ReflectiveMethodInvocation的proceed()方法也也是一样的。

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...