目录
Aop的执行顺序
我们使用spring boot写了一个简单的aop demo。
在这里我们先查看Spring Aop的执行顺序是什么样的。启动完成后我们发起请求进入aop的断点。
显然是 Around() ->Before() ->实际方法->Around()->After()->AfterReturning()或AfterThrowing()。
拦截器链的元素是这样的,那它们是以什么样的顺序执行的呢?一般来说,很多框架的拦截器链的执行方式就是把一个链表里的所有拦截器顺序执行,但这种执行方式的前提条件是这些拦截器相互独立,互不影响。也有把拦截器分为pre和post这两种方式的,比如gateway,也有要把拦截器进行排序的,它们继承了Order接口。
显然Spring Aop的拦截器模式是有明显的先后顺序的, Around() ->Before() ->实际方法->Around()->After()->AfterReturning()或AfterThrowing() 的顺序不可改变。那么只要符合这个顺序执行就行,我们可以使用递归调用的方式倒序执行。 也可以这样理解,AfterThrowing->AfterReturning->After->Around->Before这样的顺序,怎么使用一个栈达到 Around->Before->Around->After->AfterReturning->AfterThrowing这样的输出?那么得 AfterThrowing->AfterReturning->After->Around顺序入栈,在Around里包裹一个Before,然后依次出栈。 类似递归倒序的写法:参考第234题回文链表。
力扣
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
ListNode left;
public boolean isPalindrome(ListNode head) {
left = head;
return traverse(head);
}
private boolean traverse(ListNode right) {
if (right == null) {
return true;
}
boolean res = traverse(right.next);
res = res && (right.val == left.val);
left = left.next;
return res;
}
}
下面我们先分析Spring Aop 的实际执行流程,启动时的执行流程后面再分析。
实际执行流程
在网上发现了下面这张图,画得非常清晰!
ps: 来自 Spring AOP 执行流程及源码分析_spring aop执行流程源码_vnjohn的博客-CSDN博客
首先进入 ReflectiveMethodInvocation#proceed() 方法。ReflectiveMethodInvocation 实现了ProxyMethodInvocation接口。
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
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);
}
}
}
在本次的 demo 调试中,不会走下面的 if 分支代码,暂时不需要关心。
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();
}
}
首先执行的拦截器是 ExposeInvocationInterceptor。 这里面什么也没做,就是使用一个ThreadLocal保存一下 mi 调用环境。 记得我们是从 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 这里调用的,所以 ExposeInvocationInterceptor 的 mi 变量就是上文的 ReflectiveMethodInvocation 实例。
public final class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<>("Current AOP method invocation");
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
}
所以 ExposeInvocationInterceptor#invoke() 中执行的 return mi.proceed(); 又进入到ReflectiveMethodInvocation#proceed() ,这时候 this.currentInterceptorIndex 又自增了,它指向了下一个拦截器,后面会进入到下一个拦截器的代码逻辑。但等下一个拦截器的所有逻辑执行完成后会回到这里而不是直接结束,因为这是递归的。 后续的拦截器也是如此。
第二个拦截器是 AspectJAfterThrowingAdvice。主要处理一下异常。继续执行 ReflectiveMethodInvocation#proceed(),this.currentInterceptorIndex自增。
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
}
第3个拦截器是 AfterReturningAdviceInterceptor 。等 mi.proceed(); 执行完后执行一下 advice。
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
第4个拦截器 AspectJAfterAdvice 。什么都不做。注意它返回前会执行invokeAdviceMethod(getJoinPointMatch(), null, null);
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}
第5个拦截器AspectJAroundAdvice 。
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {
@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);
}
}
在AspectJAroundAdvice的执行内部,我们会执行Before的逻辑,另外,在 AspectJAroundAdvice 内部,我们必须要写 joinPoint.proceed(); 的一行代码,不然的话拦截器链的执行逻辑就会中断了。 下面是一个简单的demo。
@Around("LogAspect()")
public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable {
log.debug("deAround");
Object ret = joinPoint.proceed();
log.debug("deAround");
return ret;
}
在 AspectJAroundAdvice 执行 Around() 之后,执行 实际方法 之前,会进入到第6个拦截器,即AspectJAroundAdvice 拦截器。这个拦截器在执行下一个拦截器之前会先执行一下 before() 方法。
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
跟踪这个 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()) 代码,我们发现它执行了我们定义的before() 方法。
@Before("LogAspect()")
public void doBefore(JoinPoint joinPoint) {
log.debug("doBefore");
}
具体是这样的:
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {
protected Object invokeAdviceMethod(
@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
...
}
}
this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
就是实际的Method反射调用了。调用的是@before修饰的方法。
AspectJAroundAdvice#invoke() 执行时又进入了 ReflectiveMethodInvocation#proceed() 。但这次 this.currentInterceptorIndex 到结尾了,拦截器已经执行完了,进入 invokeJoinpoint() 方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
invokeJoinpoint() 方法就是实际要执行的方法。在demo中就是test()方法。
@GetMapping("/test")
public void test(){
System.out.println("hello world");
}
这个方法执行结束后就返回到 MethodBeforeAdviceInterceptor#invoke() 方法,这时候该方法已完成执行,回到它的父调用处,然后就回到了 AspectJAroundAdvice#invoke() 方法,此时该方法也执行完成,回到AspectJAfterAdvice#invoke()方法,在返回前会执行 invokeAdviceMethod(getJoinPointMatch(), null, null) ,它会执行@After修饰的方法。
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}
AspectJAfterAdvice#invoke()执行完毕后回到 AfterReturningAdviceInterceptor#invoke()。
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
该语句会执行@AfterReturning修饰的方法。
后面会回到 AspectJAfterThrowingAdvice#invoke()处理抛出的异常,没有异常就继续执行。
到这里Around(),Before(),After(),AfterReturn()这些钩子方法就已经执行完成了。后面回到ExposeInvocationInterceptor#invoke(), 把 mi 执行上下文重新设置回旧的执行上下文。oldInvocation一般为空。
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
启动时执行流程
<aop:aspectj-autoproxy /> 标签会往 bean 容器注入一些和 Aop 有关的 Bean,注入了哪些 bean 可以通过全局搜索这个标签字符串关键字得知,这些 Bean 在实例化和初始化的时候会做一些操作。 后面都会进入AnnotationAwareAspectJAutoProxyCreator类中开始Aop部分的执行过程。这个是所有的标签注解所共通的,就不细讲了。
在Bean容器创建 BeanPostProcessor 时期中执行 getAdvicesAndAdvisorsForBean(),wrapIfNecessary(),getEarlyBeanReference()等方法,这些是创建Bean时的三级缓存相关代码,而 Spring Aop 就是在 BeanPostProcessor 执行期间通过动态代理的方式创建的。扫描 IOC 容器中所有的 Bean ,看是否是 Aspect 类型,扫描后会继续找BeforeAdvice,AroundAdvice等切面,并用一个类封装起来。
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
再往后的两个重要方法:AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors() => findAdvisorsThatCanApply()。
因为它们是在创建 IOC 容器扫描所有的 Bean 时开始创建的,所以为了方便,我们会使用条件断点,比如我们的 Aop 切点匹配某个类 (比如是TestController) 的某个方法,那么我们就新建一个条件断点,当 beanName.contains(“testController”) 时执行这个断点。
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
里面有一行代码,就可以知道要代理的类有哪些Advice了,后面使用适配器模式转为Advisor就可以了。代理需要的材料就都准备好了。debug发现进入的是Cglib,在获取getCallbacks()的时候获得了Advice拦截器链。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
开始创建动态代理类。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
}
getInterceptorsAndDynamicInterceptionAdvice()在DefaultAdvisorChainFactory中。
我们可以在创建Cglib Aop的地方打断点。进入AbstractAutoProxyCreator中的createProxy()方法。
最后执行的细节。
@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 {
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);
List<Object> 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())) {
// 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 = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
很明显proceed()是在这里被调用的并链式执行的。这些拦截器链的名字就是adviceChain。
ReflectiveMethodInvocation 有一个唯一的子类叫 CglibMethodInvocation ,ReflectiveMethodInvocation#proceed() 方法就是在子类的地方被调用的。CglibMethodInvocation 是 CglibAopProxy 类的内部类。
未完待续。。。。