spring-AOP(一) 手动代理

spring-AOP(一) 手动代理

spring的设计原理是构造一个个原子功能,然后不断的通过设计模式在外围进行包装、组合调用,最后实现复杂的逻辑功能。

知识导读

  • 了解Aop联盟定义的几个概念,连接点、通知、拦截、切点、增强
  • ProxyFactory 定义了创建代理对象的工厂方法,不过该类主要用于提供代理配置
  • AopProxy 定义创建代理对象的接口,实现类有 jdk代理 和 cglib代理
  • 代理的本质就是对目标方法执行的拦截增强
  • 创建代理最主要是提供 被代理对象 和 增强列表 AdvisorList
  • Advisor封装了通知和切点,实质就是封装了一个可以决定在什么类的什么方法上进行增强的通知
  • 代理的最终目的就是在方法的执行前后添加逻辑,最终构建 ReflectiveMethodInvocation,创建代理类的目的就是为了实现选择性的对目标对象方法的拦截,然后将方法调用封装为ReflectiveMethodInvocation
  • Pointcut提供了怎么筛选拦截哪些对象的哪些方法
  • 切面是通知的载体,通知是个方法,切面就是定义这些方法的对象。拦截器将这些通知按照顺序串成一个链

AOP联盟和Spring扩展

AOP的实质对连接点的增强,一般通俗点讲是对对方法执行拦截增强
AOP联盟定义了AOP的规范接口,声明了两个最基础的接口,连接点 和 增强 。

连接点 Joinpoint

public interface Joinpoint {
     //连接点的执行
   Object proceed() throws Throwable;
  //一般用于返回被代理对象
   Object getThis();
  //一般用于返回目标方法的Method对象
   AccessibleObject getStaticPart();
}
fZwewP

Joinpoint(连接点) 代表一个对象可以切入的地方,一般来说就是一个方法的执行,MehtodInvocation将方法的调用过程进行了封装。spring实现扩展了MethodInvocation,在ReflectiveMethodInvocation中既实现了方法调用的封装,又定义了拦截器链,用于在方法执行过程中进行拦截增强。

通知 Advice

public interface Advice {

}

AOP联盟声明了通知的接口,用于标记通知类型,最主要的接口实现是拦截器Interceptor

public interface Interceptor extends Advice {

}
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
  //定义了对 方法调用 进行拦截的接口
   Object invoke(MethodInvocation invocation) throws Throwable;
}

在MethodInterceptor接口中声明了invoke方法,需要一个MethodInvocation对象参数。用于对方法调用进行拦截,然后执行增强逻辑,在合适的时机回调MethodInvocation,实现增强的功能

spring对MethodInterceptor接口进行了具体实现,例如提供了前置通知、后置通知、最终通知、异常通知、环绕通知的实现类。

BfRb68
d9juQF

切点 Pointcut

Pointcut是spring定义的一个接口,用于过滤目标类和匹配目标方法(连接点)

public interface Pointcut {
   //用于过滤目标类
   ClassFilter getClassFilter();
   //用于匹配目标方法
   MethodMatcher getMethodMatcher();
  
   Pointcut TRUE = TruePointcut.INSTANCE;
}

Pointcut 的具体实现,spring中Pointcut是很重的一块逻辑,可以单独出一篇文档

NscLC2

增强 Advisor

spring中定义的增强类,用于封装一个Pointcut和一个Advice,实质就是封装了一个可以决定在什么类的什么方法上应用的通知

public interface Advisor {
   Advice EMPTY_ADVICE = new Advice() {};
   //封装的通知
   Advice getAdvice();
   boolean isPerInstance();
}
public interface PointcutAdvisor extends Advisor {
   //切点,用于匹配连接点,是否应用Advice通知
   Pointcut getPointcut();
}
bgWnaP

工厂方式创建代理对象

ProxyFactory

通过ProxyFactory创建代理对象,需要配置以下信息

  1. 被代理对象
  2. 增强Advisor列表
  3. 被代理接口(非必须)
  4. 其他一些非必须配置(非必须)

下图是ProxyFactory的继承关系图,通过看各个层级的字段,可以看出ProxyFactory主要定义的是一些创建代理的配置信息。

dXcJii

AopProxy

已知的可以创建代理对象的方式

  1. 使用jdk Proxy,需要创建一个InvocationHandler的实现类,调用代理对象的方法都会去调用InvocationHandler的实现类的invoke方法,所有的拦截和增强在invoke方法中做
  2. 使用cglib的Enhancer,需要创建一批MethodInterceptor的实现类,调用代理对象所有方法都会去调用MethodInterceptor实现类的intercept方法,所有的拦截和增强都在intercept方法中做

spring中定义了一个AopProxy接口,用于获取代理类,实现类是JdkProxy和cglibProxy,ProxyFactory提供了创建AopProxy的配置信息,创建代理类对象的工作交由AopProxy的实现类实现。

X2TMay

通过ProxyFactory配置创建AopProxy实现

spring中定义了ProxyFactory用于创建代理对象,下面是创建代理对象的一个demo。

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(targetSource);//设置被代理对象
factory.setInterfaces(IUserService.class);//设置要代理的接口
proxyFactory.setProxyTargetClass(true);//设置使用cglib创建代理
proxyFactory.setExposeProxy(true);//设置是否暴露代理类
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);//设置目标类的增强 Advisor列表
return proxyFactory.getProxy(getProxyClassLoader());//创建代理类对象

调用ProxyFactory的getProxy创建代理类对象,首先会创建一个AopProxy对象,然后调用AopProxy的getProxy方法获取代理类对象,在整个创建代理类过程中,ProxyFactory用于提供配置

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

调用父类ProxyCreatorSupport中的createAopProxy创建AopProxy。

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}

在AopProxyFactory的createAopProxy创建了AopProxy的具体实现,会通过ProxyFactory中提供的配置来选择使用jdk代理还是cglib代理

注意,cglib也可以创建基于接口的代理

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      if (targetClass == null) {
         throw new AopConfigException("TargetSource cannot determine target class: " +
               "Either an interface or a target is required for proxy creation.");
      }
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

通过AopProxy创建代理类对象

创建完AopProxy之后,调用AopProxy实现类的getProxy就可以创建代理类,和代理类对象。

jdk代理

首先来分析spring是如何实现jdk代理的,在JdkDynamicAopProxy中getProxy中通过调用Proxy的api创建代理类对象

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
  //获取ProxyFactory提供的配置,接口
  Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  //调用Proxy的api创建代理类对象。
  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

由于JdkDynamicAopProxy自己本身实现了InvocationHandler接口,所以在创建代理对象的时候传递的是this

cglib代理

jdk代理比较简单,接下来看下CglibAopProxy是如何通过cglib来创建代理类对象的

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   try {
      //获取ProxyFactory配置的目标类型
      Class<?> rootClass = this.advised.getTargetClass();
      Class<?> proxySuperClass = rootClass;
      //如果当前的类型已经是cglib创建的代理类,使用代理类的父类
      if (ClassUtils.isCglibProxyClass(rootClass)) {
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) {
            this.advised.addInterface(additionalInterface);
         }
      }
      //检查下方法是否是final修饰和 private
      validateClassIfNecessary(proxySuperClass, classLoader);
     //使用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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
      //最重要的一步,组装cglib需要的拦截器实现
      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      //设置拦截器过滤器,用于指定什么方法应用什么拦截器
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);
      // enhancer创建代理
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException | IllegalArgumentException ex) {
     //此处省略代码....
   }
   catch (Throwable ex) {
      //此处省略代码....
   }
}

通过以上逻辑,spring就完成了代理类的创建,接下来对代理类的方法调用都会去调用InvocationHandler的invoke方法或者Callback的intercept方法。

代理类的方法调用

jdk代理的方法调用

zsq7Kv

JdkDynamicAopProxy实现了InvocationHandler的invoke方法,代理类对象所有方法的执行都会通过invoke方法来调用

  1. 根据Pointcut筛选应用目标方法的Advisor,将Advisor中的Advice封装为增强目标方法的拦截器链

  2. 基于拦截器链封装MethodInvocation实现类对象,方法的调用和拦截增强全由MethodInvocation实现,

注意每次目标方法执行都会新建一个MethodInvocation对象

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   //用于记录ThreadLocal中之前的代理类对象
   Object oldProxy = null;
   boolean setProxyContext = false;
   //被代理对象
   TargetSource targetSource = this.advised.targetSource;
   Object target = null;
   try {
     //此处省略代码....
      Object retVal;
          //判断如果要暴露代理类对象,如果是将代理对象放入ThreadLocal,通过AopContext.currentProxy获取
     //同时要记录下 ThreadLocal中之前存储的代理类对象,方法执行完毕后要重置回去
      if (this.advised.exposeProxy) {
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
      //最重要的一步 封装获取拦截器链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      //如果拦截器链为空,直接反射调用被代理对象的方法
      if (chain.isEmpty()) {
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }else {
         //如果存在拦截器链,构造方法调用的封装对象MethodInvocation,被代理对象方法的调用以及拦截器的增强封装都通过该类实现,每次都新建ReflectiveMethodInvocation对象,这个对象中有currentInterceptorIndex,避免污染
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         retVal = invocation.proceed();
      }
      //此处省略代码....
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // 方法执行完毕后重置ThreadLocal中的代理类对象
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

来看下spring中是如何筛选目标方法的拦截器链的,在getInterceptorsAndDynamicInterceptionAdvice会首先去获取缓存中的拦截器链,如果没有,再进行筛选解析,感觉这里还是直接new一个list,然后将cached放进去,避免后续流程修改列表

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
  //使用方法名作为缓存key,将拦截器链缓存起来,避免重复解析
   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;
}

通过DefaultAdvisorChainFactory构建拦截器链,主要就是通过Advisor中的Pointcut的ClassFilter和MethodMatcher来筛选能够增强目标方法的Advisor,然后封装为拦截器MethodInterceptor对象,组装成拦截器链返回

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, @Nullable Class<?> targetClass) {
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
   Advisor[] advisors = config.getAdvisors();//获取配置中的Advisor列表
   List<Object> interceptorList = new ArrayList<>(advisors.length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   Boolean hasIntroductions = null;
    //遍历Advisor,筛选能够增强目标方法的Advisor,并封装为拦截器链返回
   for (Advisor advisor : advisors) {
     //如果是PointcutAdvisor,判断Advisor的Pointcut是否拦截本方法
      if (advisor instanceof PointcutAdvisor) {
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
        //先通过ClassFilter判断是否拦截目标类
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            boolean match;
           //再通过MethodMatcher判断是否拦截目标方法
            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) {
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
              //如果是要根据运行时参数进行方法校验,需要封装拦截器,将methodMatcher传下去,用于执行时判断参数
               if (mm.isRuntime()) {
                  for (MethodInterceptor interceptor : interceptors) {
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  }
               }else {
                  interceptorList.addAll(Arrays.asList(interceptors));
               }
            }
         }
      }//引介增强,作用范围是类,只需判断是否拦截目标类就行
      else if (advisor instanceof IntroductionAdvisor) {
         IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
         if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
         }
      }else {//其他类型Advisor,不需要过滤,默认拦截所有方法
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      }
   }
   return interceptorList;
}

获取到目标方法的拦截器链之后,接下来构建MethodInvocation对象,调用MethodInvocation的proceed方法。在MethodInvocation中会在目标方法执行前后执行拦截器链中的增强方法,然后在合适的时机再回调目标方法,实现代理的逻辑。

通过ReflectiveMethodInvocation的构造器可以看出,该对象就是对目标方法调用和拦截器链的封装

//构造器
protected ReflectiveMethodInvocation(
            Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
            @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;//代理类对象
        this.target = target;//被代理对象
        this.targetClass = targetClass;//被代理对象类型
        this.method = BridgeMethodResolver.findBridgedMethod(method);//目标方法
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//方法参数
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//拦截器链
}

再来看如何在proceed方法完成对方法的增强,在该方法中会遍历执行拦截器链中的拦截方法,所有拦截器都执行完毕后再调用被代理类的目标方法。拦截器链是在代理类的方法中传入的,而且是缓存过的共享对象,这里避免修改该链,使用currentInterceptorIndex来记录链的执行位置。其实这块是可以进行优化的

private int currentInterceptorIndex = -1;//记录拦截器链执行第几个拦截器

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());
     //通过参数判断是否需要增强,如果需要直接调用拦截器的invoke方法,并把当前MethodInvocation传递过来,以便方法拦截逻辑执行后再次调回来
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      } else {
        //如果不进行拦截,递归,重新执行下一个拦截器.
         return proceed();
      }
   } else {
     //静态拦截器,直接调用拦截器对方法进行增强
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

ReflectiveMethodInvocation中,在执行完拦截器链中所有的拦截器逻辑之后,会调用被代理对象的目标方法,默认是通过反射调用

@Nullable
protected Object invokeJoinpoint() throws Throwable {
   return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

CglibMethodInvocation中覆写了ReflectiveMethodInvocation的invokeJoinpoint方法,会通过cglib的MethodProxy进行调用,避免反射

@Override
protected Object invokeJoinpoint() throws Throwable {
   if (this.methodProxy != null) {
      return this.methodProxy.invoke(this.target, this.arguments);
   } else {
      return super.invokeJoinpoint();
   }
}

分析到现在,AOP剩下的功能就是要看Spring中定义的几种通知类型是如何在拦截器中进行调用的。

拦截器中通知方法的执行

spring中对通知advice和拦截器MethodInterceptor的继承实现由点乱,不太明白为什么要这样做,不如分开

在拦截器中可以方便的在目标方法执行前后添加逻辑,很简单。在使用@Aspect的切面的时候,会调用@Aspect注册的bean中的方法通知。这里重点看下@Aspect是如何实现的

前置通知

首先来看下前置通知拦截器中如何调用前置通知。在invoke方法中先调用通知,然后再回调MethodInvocation目标方法

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
   //包装了一个前置通知
   private final MethodBeforeAdvice advice;
   public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
      this.advice = advice;
   }
   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      //调用前置通知方法
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());、
      //通知方法调用完毕之后,回调 连接点的方法执行
      return mi.proceed();
   }

}

AspectJMethodBeforeAdvice实现了MethodBeforeAdvice

public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {

   public AspectJMethodBeforeAdvice(
         Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
      super(aspectJBeforeAdviceMethod, pointcut, aif);
   }

   @Override
   public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
     //调用 @aspect 切面中声明的方法
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

在AbstractAspectJAdvice定义了切面方法调用过程

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 {
      ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
      //通知方法反射调用,对象是@aspect注册的bean
      return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
   }
   catch (IllegalArgumentException ex) {
      //...
   }
}

环绕通知

看完了前置通知,后置通知、异常通知基本都一样,这里看下环绕通知,环绕通知实现比较复杂

环绕通知直接调用了通知方法,在这里没有再回调目标方法的执行,因为环绕通知对目标方法的执行写在通知方法内部,接下来看环绕通知是如何完成既完成对目标方法的调用又完成剩余通知的执行

public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor{
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
       if (!(mi instanceof ProxyMethodInvocation)) {
        //...
       }
       ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
       ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
       JoinPointMatch jpm = getJoinPointMatch(pmi);
       //调用通知方法
       return invokeAdviceMethod(pjp, jpm, null, null);
    }
}

lazyGetProceedingJoinPoint返回了一个ProceedingJoinPoint,封装了原始的MethodInvocation对象

protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
   return new MethodInvocationProceedingJoinPoint(rmi);
}

接下来通知方法的调用跟前置通知一样,只不过是将ProceedingJoinPoint作为参数传递给了通知方法

@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) {
    System.out.println("around before");
    Object result = null;
    try {
        //调用原始方法
        result = p.proceed();
    } catch (Throwable e) {
    }
    System.out.println("around after");
    return result;
}

调用p.proceed() ,在 MethodInvocationProceedingJoinPoint 会将原始的 MethodInvocation克隆一份,会将剩余拦截器链和下标复制下来,然后重新调用 proceed方法

@Override
public Object proceed() throws Throwable {
   return this.methodInvocation.invocableClone().proceed();
}

ReflectiveMethodInvocation进行深克隆

@Override
public MethodInvocation invocableClone() {
   Object[] cloneArguments = this.arguments;
   if (this.arguments.length > 0) {
      // Build an independent copy of the arguments array.
      cloneArguments = new Object[this.arguments.length];
      System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length);
   }
   return invocableClone(cloneArguments);
}
@Override
public MethodInvocation invocableClone(Object... arguments) {
   ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
   clone.arguments = arguments;
   return clone;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352