第四章 Spring AOP源碼分析筆記

一、AOP的配置使用

1、AOP入口

通過掃描註解@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)註冊了AOP 入口類,具體看看註解裏面的@Import(AspectJAutoProxyRegistrar.class)

/*
* TODO 開啓註解AOP
*  替代了:<aop:aspectj-autoproxy/>
* */
@Service
@EnableAspectJAutoProxy(proxyTargetClass = false,exposeProxy = true)
public class EnableAspectJAutoProxyBean {
}

org.springframework.context.annotation.EnableAspectJAutoProxy

在這個類中,註冊了AOP入口類 AnnotationAwareAspectJAutoProxyCreator

設置了兩個屬性:

proxyTargetClass = true

1)目標對象實現了接口 – 使用CGLIB代理機制

2)目標對象沒有接口(只有實現類) – 使用CGLIB代理機制

proxyTargetClass = false

1)目標對象實現了接口 – 使用JDK動態代理機制(代理所有實現了的接口)

2)目標對象沒有接口(只有實現類) – 使用CGLIB代理機制

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   /**
    * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
    * to standard Java interface-based proxies. The default is {@code false}.
    */
   boolean proxyTargetClass() default false;
   /**
    * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
    * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
    * Off by default, i.e. no guarantees that {@code AopContext} access will work.
    * @since 4.3.1
    */
   boolean exposeProxy() default false;
}

exposeProxy

該屬性設置代理對象是否需要暴露,說白了就是是否需要把代理對象設置到ThreadLocal中。

AOP的其他入口類的配置是基於xml的形式

例如:

<!--開啓註解aop-->
<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true"/>

或者

<aop:config proxy-target-class="false">
    <!--<aop:pointcut>在此處定義的pointcut是全局的pointcut可以供所有的aspect使用-->
    <!--id:表示這個pointcut的名稱,以方便使用-->
    <aop:pointcut id="addpointcut" expression="execution(public * com.chj.service..*.add(..))"/>
    <aop:pointcut id="delpointcut" expression="execution(public * com.chj.service..*.del*(..))"/>
    <aop:pointcut id="myMethods" expression="execution(public * com.chj.service..*.*(..))"/>
    <!--advisor必須在aspect之前,要不然有xml約束報錯-->
    <aop:advisor advice-ref="beforeAdviceBean" order="2" pointcut-ref="myMethods"/>
    <aop:aspect id="aspect1" ref="aspectXml1" order="0">
        <!--<aop:declare-parents types-matching="com.zhuguang.jack.service.MyServiceImpl"-->
        <!--implement-interface="com.zhuguang.jack.aop.IntroductionIntf"-->
        <!--delegate-ref="myintroduction"/>-->
        <!--id:表示這個pointcut的名稱,以方便使用-->
        <aop:pointcut id="myMethod2" expression="execution(public * com.chj.service..*.*(..))
            and @annotation(org.springframework.web.bind.annotation.RequestMapping)"/>
        <aop:before method="before" pointcut-ref="myMethods"/>
        <aop:after method="after" pointcut-ref="myMethod2"/>
        <!-- 後置通知  returning="returnVal" 定義返回值 必須與類中聲明的名稱一樣-->
        <aop:after-returning method="afterReturning" returning="returnVal"
                             pointcut="execution(public * com.chj.service..*.*(..))"/>
        <!--異常通知 throwing="throwable" 指定異常通知錯誤信息變量,必須與類中聲明的名稱一樣-->
        <!--<aop:after-throwing method="afterthrowing" throwing="e" pointcut-ref="myMethods"/>-->
        <aop:around method="around" pointcut-ref="myMethod2"/>
    </aop:aspect>
</aop:config>

2、是否生成代理

當一個bean實例化完成後,會判斷該bean是否生成代理,AOP的入口如下:

2.1、Aop代理對象生產入口:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

// Initialize the bean instance.
Object exposedObject = bean;
try {
   //ioc di,依賴注入的核心方法,該方法必須看,重要程度:5
   populateBean(beanName, mbd, instanceWrapper);
   //bean 實例化+ioc依賴注入完以後的調用,非常重要,重要程度:5
   exposedObject = initializeBean(beanName, exposedObject, mbd);
}

在這個方法裏面,具體是:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String,Object, RootBeanDefinition)

if (mbd == null || !mbd.isSynthetic()) {
   //這個地方可能生出代理實例,是aop的入口
   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;

這是一個BeanPostProcessor接口的運用,initializeBean方法我們都知道是一個bean實例化完成後做的操作,而這個代理實例生成也是在bean實例化完成後做的操作,其核心代碼如下:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {
   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

2.2、如果這個bean有advice的話創建當前bean的代理

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

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;
   }
   //創建當前bean的代理,如果這個bean有advice的話,重點看,重要程度5
   // Create proxy if we have advice.
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   //如果有切面,則生成該bean的代理
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      //把被代理對象bean實例封裝到SingletonTargetSource對象中
      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;
}

這個方法就是判斷當前bean是否有切面advisor,如果有切面就會走到createProxy方法,生成代理對象然後返回。

2.3、尋找當前bean的切面簡單來說就兩步:

第一步:從spring中找所有的切面,然後找到合格的切面

找到候選的切面,其實就是一個尋找有@Aspectj註解的過程,把工程中所有有這個註解的類封裝成Advisor返回;判斷候選的切面是否作用在當前beanClass上面,就是一個匹配過程,現在就是一個匹配。

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean();

@Override
@Nullable
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) {
   //找到候選的切面,其實就是一個尋找有@Aspectj註解的過程,把工程中所有有這個註解的類封裝成Advisor返回
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   //判斷候選的切面是否作用在當前beanClass上面,就是一個匹配過程。。現在就是一個匹配
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      //對有@Order@Priority進行排序
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

第二步:找到攔截當前bean的切面

從spring中找所有切面, 先找到所有的beanDefinition對象對應的beanName,拿到對應的Class對象,判斷該類上面是否有@Aspect註解,如果有則是我們要找的,循環該Class裏面的除了@PointCut註解的方法,找到方法上面的Around.class,Before.class, After.class, AfterReturning.class, AfterThrowing.class 註解,並且把註解裏面的信息,比如表達式:argNames,註解類型等信息封裝成對象AspectJAnnotation,然後創建pointCut對象,把註解對象中的表達式設置到pointCut對象中,然後就是創建Advice對象,根據不同的註解類型創建出不同的Advice對象,對象如下:

AspectJAroundAdvice,AspectJAfterAdvice,AspectJAfterThrowingAdvice,AspectJMethodBeforeAdvice,AspectJAfterReturningAdvice最終把註解對應的Advice對象和pointCut對象封裝成Advisor對象。

protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
      //看看當前類是否在這些切面的pointCut中
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
   } finally {
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}

找到攔截當前bean的切面:

從收集到的所有切面中,每一個切面都會有pointCut來進行模塊匹配,其實這個過程就是一個匹配過程,看看pointCut表達式中的內容是否包含了當前bean,如果包含了,那麼這個bean就有切面,就會生成代理。

//創建當前bean的代理,如果這個bean有advice的話,重點看,重要程度5
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//如果有切面,則生成該bean的代理
if (specificInterceptors != DO_NOT_PROXY) {
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
   //把被代理對象bean實例封裝到SingletonTargetSource對象中
   Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
   this.proxyTypes.put(cacheKey, proxy.getClass());
   return proxy;
}

二、代理類的調用

1、代理類調用入口

當判斷bean有切面時也就是

//如果有切面,則生成該bean的代理
if (specificInterceptors != DO_NOT_PROXY) {
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
   //把被代理對象bean實例封裝到SingletonTargetSource對象中
   Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
   this.proxyTypes.put(cacheKey, proxy.getClass());
   return proxy;
}

這個數組不爲空時,就會往下走,走到createProxy方法裏面,這個方法就會生成bean的代理實例。

2、創建代理的過程:

1)創建代理工廠對象ProxyFactory

2)切面對象重新包裝,會把自定義的MethodInterceptor類型的類包裝成Advisor切面類並加入到代理工廠中

3)根據proxyTargetClass參數和是否實現接口來判斷是採用jdk代理還是cglib代理

4)創建代理對象,並且把代理工廠對象傳遞到jdk和cglib中,注意這裏的代理對象和jdk類和cglib類是一一對應的。

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

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)) {
         //proxyTargetClass 是否對類進行代理,而不是對接口進行代理,設置爲true時,使用CGLib代理。
         proxyFactory.setProxyTargetClass(true);
      }else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
   //把advice類型的增強包裝成advisor切面
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   proxyFactory.addAdvisors(advisors);
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);
   //用來控制代理工廠被配置後,是否還允許修改代理的配置,默認爲false
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
   //獲取代理實例
   return proxyFactory.getProxy(getProxyClassLoader());
}

3、獲取代理實例

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

/獲取代理實例
return proxyFactory.getProxy(getProxyClassLoader());

org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)

public Object getProxy(@Nullable ClassLoader classLoader) {
   //根據目標對象是否有接口來判斷採用什麼代理方式,cglib代理還是jdk動態代理
   return createAopProxy().getProxy(classLoader);
}

 

org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy

org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy

判斷是使用JDK代理還是cglib動態代理實現:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
   @Override
   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.");
         }

// 判斷代理類是否實現了接口(如果是使用JDK動態代理)
         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      } else {
         return new JdkDynamicAopProxy(config);
      }
   }

4、代理實例的調用

上面我們已經創建出來了代理對象了,現在是拿到代理對象調用,以 jdk動態代理爲例,cglib是一樣的調用邏輯。

當發生代理對象調用時,肯定會調用到實現了invocationHandler接口的類,這個類就是:JdkDynamicAopProxy必定會調用到該類的invoke方法。

我們看看invoke方法:

org.springframework.aop.framework.JdkDynamicAopProxy#invoke

if (this.advised.exposeProxy) {
   // Make invocation available if necessary.
   oldProxy = AopContext.setCurrentProxy(proxy);
   setProxyContext = true;
}

該參數如果爲true會把代理對象存放到ThreadLocal中。我們在代理裏面通過AopContext.currentProxy方法就可以拿到當前調用的代理類。實際上沒啥用。

// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
//這個target就是被代理實例
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//從代理工廠中拿過濾器鏈 Object是一個MethodInterceptor類型的對象,其實就是一個advice對象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)

public Object getProxy(@Nullable ClassLoader classLoader) {
   //根據目標對象是否有接口來判斷採用什麼代理方式,cglib代理還是jdk動態代理
   return createAopProxy().getProxy(classLoader);
}

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   //advised是代理工廠對象
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

從代理工廠中拿到切面,並且跟當前被代理類和當前被調用方法匹配,如果匹配就返回切面中的advice對象,這就是advice執行鏈。只是對advice進行了統一包裝,如下代碼:

5、advice執行鏈

方法入口:org.springframework.aop.framework.JdkDynamicAopProxy#invoke

//從代理工廠中拿過濾器鏈 Object是一個MethodInterceptor類型的對象,其實就是一個advice對象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice

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;
}

5.1、獲取過濾器鏈

org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

@Override
public List<Object> 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,config就是代理工廠對象
   Advisor[] advisors = config.getAdvisors();
   List<Object> interceptorList = new ArrayList<>(advisors.length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   Boolean hasIntroductions = null;
   for (Advisor advisor : advisors) {
      //大部分走這裏
      if (advisor instanceof PointcutAdvisor) {
         // Add it conditionally.
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
         //如果切面的pointCut和被代理對象是匹配的,說明是切面要攔截的對象
         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 {
               //接下來判斷方法是否是切面pointcut需要攔截的方法
               match = mm.matches(method, actualClass);
            }
            //如果類和方法都匹配
            if (match) {
               //獲取到切面advisor中的advice,並且包裝成MethodInterceptor類型的對象
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
               if (mm.isRuntime()) {
                  // Creating a new object instance in the getInterceptors() method
                  // isn't a problem as we normally cache created chains.
                  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 {
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      }
   }
   return interceptorList;
}

5.2、獲取到切面advisor中的advice,並且包裝成MethodInterceptor類型的對象

org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#getInterceptors

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
   List<MethodInterceptor> interceptors = new ArrayList<>(3);
   Advice advice = advisor.getAdvice();
   //如果是MethodInterceptor類型的,如:AspectJAroundAdvice
   //AspectJAfterAdvice
   //AspectJAfterThrowingAdvice
   if (advice instanceof MethodInterceptor) {
      interceptors.add((MethodInterceptor) advice);
   }
   //處理 AspectJMethodBeforeAdvice  AspectJAfterReturningAdvice
   for (AdvisorAdapter adapter : this.adapters) {
      if (adapter.supportsAdvice(advice)) {
         interceptors.add(adapter.getInterceptor(advisor));
      }
   }
   if (interceptors.isEmpty()) {
      throw new UnknownAdviceTypeException(advisor.getAdvice());
   }
   return interceptors.toArray(new MethodInterceptor[0]);
}

org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#getInterceptors

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
   List<MethodInterceptor> interceptors = new ArrayList<>(3);
   Advice advice = advisor.getAdvice();
   //如果是MethodInterceptor類型的,如:AspectJAroundAdvice
   //AspectJAfterAdvice
   //AspectJAfterThrowingAdvice
   if (advice instanceof MethodInterceptor) {
      interceptors.add((MethodInterceptor) advice);
   }
   //處理 AspectJMethodBeforeAdvice  AspectJAfterReturningAdvice
   for (AdvisorAdapter adapter : this.adapters) {
      if (adapter.supportsAdvice(advice)) {
         interceptors.add(adapter.getInterceptor(advisor));
      }
   }
   if (interceptors.isEmpty()) {
      throw new UnknownAdviceTypeException(advisor.getAdvice());
   }
   return interceptors.toArray(new MethodInterceptor[0]);
}

 

5.3、默認創建的增強:

private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
public DefaultAdvisorAdapterRegistry() {
   registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
   registerAdvisorAdapter(new AfterReturningAdviceAdapter());
   registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

6、Aop鏈式調用過程

最終會把箭頭指向的這兩種類型的advice包裝成MethodInterceptor類型的advice,方便後續統一調用。

org.springframework.aop.framework.JdkDynamicAopProxy#invoke

else {
   // We need to create a method invocation...
   invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
   // Proceed to the joinpoint through the interceptor chain.
   retVal = invocation.proceed();
}

獲取到這個執行鏈後,判斷如果執行鏈爲空,則直接反射調用方法,說明該方法沒被攔截,如果不爲空就會有一個鏈式調用過程。

6.1、在ReflectiveMethodInvocation中維護了執行鏈數組和數組索引

@Override
@Nullable
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   //如果執行鏈中的advice全部執行完,則直接調用joinPoint方法,就是被代理方法
   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.
      //調用MethodInterceptor中的invoke方法
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

6.2、通過索引獲取到數組裏面的advice然後調用mi.proceed()

我們舉例說明,如果第一個advice調用到了beforeAdvice,如下:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
   private final MethodBeforeAdvice advice;
   /**
    * Create a new MethodBeforeAdviceInterceptor for the given advice.
    * @param advice the MethodBeforeAdvice to wrap
    */
   public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
      Assert.notNull(advice, "Advice must not be null");
      this.advice = advice;
   }
   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
      return mi.proceed();
   }
}

BeforeAdvice首先會調用自己advice對象中的method對象,而這個method對象就是有@Before註解的方法,我們通過解析方法上面的註解類型生成advice對象時把對應的method對象封裝到了advice對象中,所以這裏就只要反射調用method對象即可。

6.3、Before方法與around方法鏈式調用

調用完後,這裏有一個mi.proceed()這個方法又會回到ReflectiveMethodInvocation這個類中

@Override
@Nullable
public Object proceed() throws Throwable {

//調用MethodInterceptor中的invoke方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

這時候索引又會+1,然後從鏈中後去下一個advice,然後下一個advice調用完後再mi.proceed()又會接着調用,其中後置增強是通過在finally塊中執行的,就這樣形成了一個鏈式調用過程。直到數組鏈中全部調用完後會調用到具體的joinPoint方法如下:

@Override
@Nullable
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   //如果執行鏈中的advice全部執行完,則直接調用joinPoint方法,就是被代理方法
   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.
      //調用MethodInterceptor中的invoke方法
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

當判斷當前索引==執行鏈數組大小時就會調用到被代理方法,完成aop增強過程。

6.4、後置after增強處理方法

org.springframework.aop.aspectj.AspectJAfterAdvice#invoke

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

三、AOP代理總結

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章