h

hitechr

V1

2022/08/26阅读:21主题:极客黑

AOP的原理:代理对象的执行过程

前情回顾

当我们用@EnableAspectJAutoProxy@Aspect@Pointcut@Before等注解配置好代理后,项目启动时首先会被ConfigurationClassPostProcessor解析到EnableAspectJAutoProxy导入的AspectJAutoProxyRegistrar这个类,这个类会往spring容器中注册一个AnnotationAwareAspectJAutoProxyCreator的定义信息,因为这个类实现了InstationAwareBeanPostProcessor接口,所以会在一个类的实力话前调用postProcessorBeforeInstation去解析被@Aspect修饰的类,然后在遍历这个类的所有方法,找出被@Before@After@Around修饰的方法,根据Pointcut生成AspecJExpectionPointcut,在结合Method为每个连接点生成一个Advice的实现类(AspectJ****Advice),再把Advice包装为一个Advisor,在返回Advisor集合前会为这个集合添加一个ExposeInvocationInterceptor,排序后进行返回。

一个对象创建好后,会调用到AnnotationAwareAspectJAutoProxyCreatorpostProcessorAfterInitialization方法,在这个方法里进行代理的创建,用Fastclass来生成一个代理类,并把满足条件的Advisor集合和DynamicAdvisedInterceptor设置到代理类中。

执行过程

cglib生成的代理类是覆盖父类中的方法,在重写的方法里面调用MethodInterceptor#inteceptor方法进行中转调用目标类的真实方法,在调用真实方法前会经过一些列的Advisor方法的调用对其进行拦截。 查看根据上篇的代码生成CGLIB代理类的代理方法

从生成的代码可以,它是调用了CGLIB$CALLBACK_0的intercept方法,把当前对象this、被代理方法CGLIB 0$Method、MethodProxy对象以及参数传递过去

再看下CGLIB$CALLBACK_0是哪个对象?

在创建代理类时有调用到setCallbacks,给代理设置回调,CGLIB$CALLBACK_0为回调的数组的第一个参数值

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        //AOP代理的核心对象
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
       。。。。。
        Callback targetDispatcher = (isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };
        。。。。。
        return callbacks;
}

由此可见当执行代理类的方法里,首先会进入到DynamicAdvisedInterceptor对象的interceptor方法里。


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 {
               
                // 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);//目标class
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                   。。。。。
                }
                else {
                    // 通过CglibMethodInvocation执行chain链
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                。。。。
            }
        }

然后执行advised的getInterceptorsAndDynamicInterceptionAdvice方法获取可以执行链,遍历Advisor集合,然后与当前方法是否匹配,如果匹配则在从Advisor中获取出Advice(MethoInterceptor),然后放到缓存中。当拿到Advice集合后,会走到CglibMethodInvocation#processed处去执行。

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    }
    。。。。
}
public Object proceed() throws Throwable {
    //当前执行到的索引号是不是最后一个
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();//执行定义的连接点方法@Before\@After
    }
    //获取chain链上的下个Advice(MethodInterceptor)
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
       //在getAdvice时封装的为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);//执行advice的invoke方法
        }else {
            return proceed();//跳过当前的
        }
    }else {
        ////执行advice的invoke方法
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

interceptor.invoke处其实就已经执行了定义好的连接点的方法。

如果是@Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptorBeforeAdviceSerializable {
 private final MethodBeforeAdvice advice;
  。。。。
 public Object invoke(MethodInvocation mi) throws Throwable {
    //此处是通过反射调用定义的方法 
  this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
  return mi.proceed();
 }
}

如果是@After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
  implements MethodInterceptorAfterAdviceSerializable 
{
。。。。
 public Object invoke(MethodInvocation mi) throws Throwable {
  try {
      //先去执行链上的方法
   return mi.proceed();
  }finally {
    //再去执行定义的方法
   invokeAdviceMethod(getJoinPointMatch(), nullnull);
  }
 }
}

总结

  1. 代理类被调用时首先要通过生成的代理类中覆盖的方法
  2. 然后会调用DynamicAdvisedInterceptor中的intercept方法
  3. 在这上方法中从能Advisor获取满足条件的Advice
  4. 在通过CglibMethodInvocation中的proceed方法,获取所执行的Advice
  5. 然后在Advice的inoke方法中回到Advice的链上继续获取Advice,如果是最后一个,则去执行目标方法,最后再逐步返回。

分类:

后端

标签:

Java

作者介绍

h
hitechr
V1