Spring AOP 實(shí)現(xiàn)源碼分析

1. AOP 概念

AOP(Aspect Oriented Programming),即面向切面編程。

  • 連接點(diǎn)(JoinPoint)
    程序執(zhí)行的某個(gè)特定位置:如類開(kāi)始初始化前、類初始化后、類某個(gè)方法調(diào)用前、調(diào)用后、方法拋出異常后。一個(gè)類或一段程序代碼擁有一些具有邊界性質(zhì)的特定點(diǎn),這些點(diǎn)中的特定點(diǎn)就稱為“連接點(diǎn)”。Spring僅支持方法的連接點(diǎn),即僅能在方法調(diào)用前、方法調(diào)用后、方法拋出異常時(shí)以及方法調(diào)用前后這些程序執(zhí)行點(diǎn)織入增強(qiáng)。
  • 切點(diǎn)(Pointcut)
    每個(gè)類具有多個(gè)連接點(diǎn),如果一個(gè)類擁有15個(gè)方法,那么這些方法都是連接點(diǎn),連接點(diǎn)相當(dāng)于數(shù)據(jù)庫(kù)中的記錄,而切點(diǎn)相當(dāng)于查詢條件。切點(diǎn)和連接點(diǎn)不是一對(duì)一的關(guān)系,一個(gè)切點(diǎn)可以匹配多個(gè)連接點(diǎn)。Spring AOP的規(guī)則解析引擎負(fù)責(zé)切點(diǎn)所設(shè)定的查詢條件,找到對(duì)應(yīng)的連接點(diǎn)。其實(shí)確切地說(shuō),不能稱之為查詢連接點(diǎn),因?yàn)檫B接點(diǎn)是方法執(zhí)行前、執(zhí)行后等包括方位信息的具體程序執(zhí)行點(diǎn),而切點(diǎn)只定位到某個(gè)方法上,所以如果希望定位到具體連接點(diǎn)上,還需要提供方位信息。
  • 增強(qiáng)(Advice)
    增強(qiáng)是織入到目標(biāo)類連接點(diǎn)上的一段程序代碼,在Spring中,增強(qiáng)除用于描述一段程序代碼外,還擁有另一個(gè)和連接點(diǎn)相關(guān)的信息,這便是執(zhí)行點(diǎn)的方位。結(jié)合執(zhí)行點(diǎn)方位信息切點(diǎn)信息,我們就可以找到特定的連接點(diǎn)。
  • 通知器(Advisor)
    當(dāng)我們完成切面增強(qiáng)設(shè)計(jì)(Advice)和切入點(diǎn)的設(shè)計(jì)(Pointcut),需要一個(gè)對(duì)象把他們結(jié)合起來(lái),Advisor 就是起到這個(gè)作用,通過(guò)Advisor ,可以確定在哪個(gè)Pointcut 使用哪個(gè)Advice。所以一個(gè)Advisor包含一個(gè)Advice 和 一個(gè)Pointcut 信息。

2. 一些疑問(wèn)

  1. Spring AOP 增強(qiáng)的代理類 在什么時(shí)候創(chuàng)建 ?
  2. Spring AOP 怎樣為一個(gè)類 和 方法 匹配 增強(qiáng)的 ?
  3. Spring AOP 是如何 協(xié)調(diào) 前置通知 后置通知 異常通知 返回通知的?
  4. 切面類 可以被 AOP增強(qiáng)么?

3. 注冊(cè) AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator是用來(lái)處理 當(dāng)前項(xiàng)目當(dāng)中 所有 AspectJ 注解的切面類。以及所有的 Spring Advisor ,同時(shí) 也是一個(gè) BeanPostProcessor 。所以 想了解Spring AOP 如何實(shí)現(xiàn),就要先分析 AnnotationAwareAspectJAutoProxyCreator,那么他從何而來(lái),是如何注冊(cè)到容器內(nèi)的。
注冊(cè)AnnotationAwareAspectJAutoProxyCreator方式:

  1. 使用 EnableAspectJAutoProxy注解,改注解 又被 @Import 注解注釋,向容器中注冊(cè)了AspectJAutoProxyRegistrar,最后由 AspectJAutoProxyRegistrar 向容器中注冊(cè) AnnotationAwareAspectJAutoProxyCreator。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //向容器注冊(cè) AnnotationAwareAspectJAutoProxyCreator
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        //對(duì)proxyTargetClass 屬性的支持,切換JDK代理 和 CGLIB 代理
        if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        //是否對(duì) AopContext.currentPoxy支持。
        if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }
}
  1. 使用 @EnableAutoConfiguration注解。改注解會(huì)向容器注冊(cè)Spring.factories文件中聲明的類,其中AopAutoConfiguration是對(duì)Spring AOP自動(dòng)配置的支持。
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
    @Configuration
    最終還是通過(guò) EnableAspectJAutoProxy 注冊(cè)AnnotationAwareAspectJAutoProxyCreator
    @EnableAspectJAutoProxy(proxyTargetClass = false)
    判斷條件 ,可以在 application.properties 中 配置。
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
    public static class JdkDynamicAutoProxyConfiguration {
    }
    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
    public static class CglibAutoProxyConfiguration {
    }
}
  1. xml 標(biāo)簽
    Spring 采用 自定義標(biāo)簽 <aop:aspectj-autoproxy /> 注冊(cè)AnnotationAwareAspectJAutoProxyCreator

4. AnnotationAwareAspectJAutoProxyCreator的初始化

AnnotationAwareAspectJAutoProxyCreator初始化 主要初始一些 組件對(duì)象。

組件包括:

  • AspectJAdvisorFactory
    根據(jù)AspectJ 注釋的切面類 創(chuàng)建 Spring AOP Advisors 的工廠接口。Advisor增強(qiáng)器的創(chuàng)建 都是由AspectJAdvisorFactory完成。
  • BeanFactoryAspectJAdvisorsBuilder
    從項(xiàng)目中 查找所有的切面類,然后使用 AspecJAdvisorFactory 創(chuàng)建 Advisors。
  • advisorRetrievalHelper
    對(duì)Xml 配置Advisor 的支持。從容器中檢索 所有的 Advisor 類型。

5 . 創(chuàng)建代理類過(guò)程

由于 AnnotationAwareAspectJAutoProxyCreator 是一個(gè) BeanPostProcessor 實(shí)現(xiàn)類,Spring 會(huì)在對(duì)一個(gè)對(duì)象的初始化前后執(zhí)行 BeanPostProcssor 的接口方法。Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;就是 創(chuàng)建增強(qiáng)代理對(duì)象的方法。該方法被AnnotationAwareAspectJAutoProxyCreator的父類AbstractAutoProxyCreator實(shí)現(xiàn)。

  • postProcessAfterInitialization
@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    //bean 就是需要 被增強(qiáng)的類。
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //防止 bean 多次被增強(qiáng)。
            if (!this.earlyProxyReferences.contains(cacheKey)) {
            //如果有必要 就進(jìn)行封裝,有沒(méi)有必要主要取決于 bean 是否需要被增強(qiáng)。
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
  • wrapIfNecessary
    對(duì)給定bean 就行封裝。
/**
     *如果有必要 封裝 bean
     */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//如果已經(jīng)處理過(guò)
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
//如果不需要增強(qiáng) 就直接返回
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        //如果是一個(gè) 組件類,組件類包括Advice,Pointcut,Advisor,AopInfrastructureBean實(shí)現(xiàn)類,和 Aspect注解注釋的類。所以 切面類 自己不會(huì)被AOP 增強(qiáng)。
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
        // 為bean 獲取和 匹配合適的 增強(qiáng)器 
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        //如果 沒(méi)有 匹配到增強(qiáng)器 那么就不用創(chuàng)建增強(qiáng)代理類。
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            //創(chuàng)建 增強(qiáng)代理類
            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;
    }
5.1 獲取增強(qiáng)器
  • getAdvicesAndAdvisorsForBean(為bean獲取和匹配合適的增強(qiáng)器)
    getAdvicesAndAdvisorsForBean ---> findEligibleAdvisors:

    為bean獲取和匹配增強(qiáng)器分為兩步:

5.1.1 獲取到所有的增強(qiáng)器
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    
    //獲取所有的增強(qiáng)器
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //匹配合適的增強(qiáng)器
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }
  • findCandidateAdvisors 獲取到所有的增強(qiáng)器
    調(diào)用AnnotationAwareAspectjAutoProxyCreator 的 findCandidateAdvisors
    @Override
    protected List<Advisor> findCandidateAdvisors() {
       // 對(duì)xml 配置 Advisor 的支持.
       List<Advisor> advisors = super.findCandidateAdvisors();
       // 搜索容器中所有 @Aspecj 注解申明的 切面類,構(gòu)建增強(qiáng)器
       advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
       return advisors;
    }
    
  • aspectJAdvisorsBuilder.buildAspectJAdvisors()
    代碼比較多,就不粘出來(lái)了,大致邏輯就是
  1. 獲取容器中已經(jīng)注冊(cè)的BeanNames
  2. 遍歷 所有已經(jīng)注冊(cè)的Bean,查找 @AspectJ
  3. 通過(guò)AspectJAdvisorFactory獲取Advisor。怎么獲取的 就不解釋了。
5.1.2 匹配合適的增強(qiáng)器

匹配合適的增強(qiáng)器,Spring 使用了 AopUtils.canApply。

匹配邏輯就是:

遍歷 所有增強(qiáng)器,采用增強(qiáng)器的 Poincut 對(duì)一個(gè)對(duì)象的所有方法進(jìn)行匹配,一旦有方法匹配到,就返回true.

對(duì)方法的匹配需要遍歷 所有方法 一一就行匹配。

5.2 創(chuàng)建 代理類

通過(guò) ProxyFactory 創(chuàng)建動(dòng)態(tài)代理類,創(chuàng)建之前 先配置ProxyFactory,設(shè)置目標(biāo)對(duì)象,設(shè)置是否對(duì)目標(biāo)對(duì)象代理(會(huì)影響采用JDK代理或者Cglib代理),設(shè)置增強(qiáng)器集合,等。

配置ProxyFactory完成之后就是獲取代理類了,

調(diào)用ProxyFactory.getProxy:

public Object getProxy(ClassLoader classLoader) {
    //先獲取 AopProxy,AopProxy有JDK實(shí)現(xiàn)和 Cglib實(shí)現(xiàn)兩種。
        return createAopProxy().getProxy(classLoader);
}

判斷采取JDK代理 或Cglib代理。
判斷條件:

  1. Optimize: 是否采用了 激進(jìn)的優(yōu)化策略,該優(yōu)化僅支持 Cglib代理
  2. ProxyTargetClass: 代理目標(biāo)類,代理目標(biāo)類 就是采用 子類繼承的方式創(chuàng)建代理,所以也是Cglib代理,可以通過(guò)。
  3. hasNoUserSuppliedProxyInterfaces:判斷是否是實(shí)現(xiàn)了接口,如果沒(méi)有必須采用Cglib代理。
    所以如果我們想在項(xiàng)目中 采用Cglib代理的話 application.properties中配置:
    spring.aop.proxy-target-class=false,或者使用注解配置proxyTargetClass = true .
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //判斷采用什么代理類型。
    //Optimize 是否采用了 激進(jìn)的優(yōu)化策略,該優(yōu)化僅支持 Cglib代理
    //ProxyTargetClass 代理目標(biāo)類,代理目標(biāo)類 就是采用 子類繼承的方式創(chuàng)建代理,所以也是Cglib代理,可以通過(guò)
    // 判斷是否是實(shí)現(xiàn)了接口,如果沒(méi)有必須采用Cglib代理。
        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.");
            }
            如果目標(biāo)對(duì)象是接口 采用 JDK代理。
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
           
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

  • 拿JdkDynamicAopProxy來(lái)說(shuō)。

獲取代理類:

JDK動(dòng)態(tài)代理的關(guān)鍵是 InvocationHandler,JdkDynamicAopProxy實(shí)現(xiàn)了InvocationHandler接口。

@Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        //獲取代理類,其中InvocationHanler 是 this,就是JdkDynamicAopProxy。
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

6.增強(qiáng)方法的執(zhí)行

增強(qiáng)方法的執(zhí)行 是AOP的核心所在,理解Spring Aop 是如何 協(xié)調(diào) 各種通知 的執(zhí)行,是理解的關(guān)鍵。

通知 分為前置 后置 異常 返回 環(huán)繞通知,在一個(gè)方法中每種通知的執(zhí)行時(shí)機(jī)不同,協(xié)調(diào)他們之間執(zhí)行順序很重要。

但是Spring AOP 采用了很聰明的方法讓各種各樣的通知準(zhǔn)確有序的工作。

  • JdkDynamicAopProxy.invoker

由于invoker 方法很大,我刪除了大部分的代碼,保留幾處關(guān)鍵代碼:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //省略了 對(duì) hashCode equals 等方法的處理....
    //exposeProxy屬性的支持。
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            // 獲取目標(biāo)對(duì)象類
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
      // 獲取攔截器鏈 這里this.advised 就是AnnotationAwareAspectJAutoProxyCreator
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
     //如果 沒(méi)有攔截器鏈 則直接執(zhí)行。
      if (chain.isEmpty()) {
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {    
          //開(kāi)始執(zhí)行攔截器鏈
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         retVal = invocation.proceed();
      }
    //返回執(zhí)行結(jié)果。
      return retVal;
  
}
6.1 創(chuàng)建攔截器鏈

攔截器鏈InterceptorAndDynamicMethodMatcher 類 和 MethodInterceptor 類型的集合。

InterceptorAndDynamicMethodMatcher 封裝了 MethodInterceptor 和 MethodMather ,作用就是在執(zhí)行時(shí)進(jìn)行再次匹配。

創(chuàng)建攔截器的過(guò)程就是 對(duì)所有 適合 目標(biāo)類的 Advisor進(jìn)行再一次篩選。對(duì)匹配的Advisor封裝成 MethodInterceptor。通過(guò)MethodInterceptor 統(tǒng)一 增強(qiáng)方法的調(diào)用。

6.2 執(zhí)行攔截器鏈

使用ReflectiveMethodInvocation 對(duì)連接器鏈進(jìn)行封裝。通過(guò)process 方法觸發(fā)攔截器開(kāi)始執(zhí)行。

public Object proceed() throws Throwable {
        //  判斷攔截器鏈 是否執(zhí)行結(jié)束,如果執(zhí)行結(jié)束執(zhí)行目標(biāo)方法。
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        //獲取下一個(gè) 需要執(zhí)行的 攔截器
        Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //如果需要執(zhí)行時(shí) 進(jìn)行匹配
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            //如果匹配,并不清楚 為什么還要在這里 進(jìn)行再次匹配。
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) 
            //注意這里 將ReflectiveMethodInvocation 自己當(dāng)參數(shù) ,傳入調(diào)用。
                return dm.interceptor.invoke(this);
            }
            else {
            //遞歸的調(diào)用
                return proceed();
            }
        }
        else {
            //如果 MethodInterceptor 
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

查看代碼并沒(méi)有發(fā)現(xiàn)任何的關(guān)于協(xié)調(diào)前置,后置各種通知的代碼。其實(shí)所有的協(xié)調(diào)工作都是由MethodInterceptor 自己維護(hù)。

  • 前置MethodInterceptor(MethodBeforeAdviceInterceptor)的invoke
    @Override
  public Object invoke(MethodInvocation mi) throws Throwable {
        //激活 前置增強(qiáng)方法
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        //繼續(xù)調(diào)用下一個(gè) 攔截器。
      return mi.proceed();
  }

  • 后置MethodInterceptor(AspectJAfterAdvice)

    @Override
      public Object invoke(MethodInvocation mi) throws Throwable {
          try {
                //繼續(xù)調(diào)用一下攔截器。
              return mi.proceed();
          }
          finally {
                //在finally 里面激活 后置增強(qiáng)方法
              invokeAdviceMethod(getJoinPointMatch(), null, null);
          }
      }
    

    通過(guò)對(duì)比前置 和 后置 攔截器,可以發(fā)現(xiàn) 具體協(xié)調(diào)各種通知 的 邏輯 實(shí)際是利用了 遞歸的思想。
    后置攔截器為例: 先執(zhí)行 遞歸方法 proceed()。最后從遞歸方法返回的時(shí)候 最后調(diào)用 后置方法。

7. 模擬攔截器調(diào)用

為了更好理解 攔截器調(diào)用,自己實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的攔截器鏈調(diào)用過(guò)程。

7.1 準(zhǔn)備工作
  • 接口

    //方法調(diào)用   
    interface MethodInvocation{
             Object process() throws Throwable;
        }
    //方法攔截器
        interface MethodInterceptor{
            Object invoke(MethodInvocation mi) throws Throwable;
        }
    
  • 實(shí)現(xiàn)

    //后置增強(qiáng)方法的 攔截器
    
    class AfterMethodInterceptor implements MethodInterceptor{
            String identification;
            public AfterMethodInterceptor(String identification){
                this.identification = identification;
            }
            @Override
            public Object invoke(MethodInvocation mi) throws Throwable {
                try {
                    return mi.process();
                }finally {
                    System.out.println("執(zhí)行后置通知"+identification);
                }
            }
        }
    //前置 的 方法攔截器 
        class BeforMethodInterceptor implements MethodInterceptor{
            String identification;
            public BeforMethodInterceptor(String identification){
                this.identification = identification;
            }
            @Override
            public Object invoke(MethodInvocation mi) throws Throwable {
                System.out.println("執(zhí)行前置通知"+identification);
                return mi.process();
            }
        }
    // 默認(rèn)的 方法調(diào)用實(shí)現(xiàn)
     class DefaultMethodInvacation implements MethodInvocation {
            List<MethodInterceptor> chian;
            Object target; //目標(biāo)對(duì)象
            Method method; //目標(biāo)方法
            Object[] args; //方法參數(shù)
            int currentChianIndex; //記錄攔截器鏈當(dāng)前執(zhí)行位置
            public  DefaultMethodInvacation(List<MethodInterceptor> chian,Object target,Method method,Object[] args){
                this.chian = chian;
                this.method = method;
                this.target = target;
                this.args = args;
            }
            @Override
            public Object process() throws Throwable{
                Object value ;
                //如果 攔截器 執(zhí)行完畢 執(zhí)行 目標(biāo)方法
                if(currentChianIndex == chian.size()){
                    value = method.invoke(target, args);
                    return value;
                }
                //獲取下一個(gè) 攔截器
                MethodInterceptor methodInterceptor = chian.get(currentChianIndex++);
                return methodInterceptor.invoke(this);
            }
        }
    //目標(biāo)對(duì)象
    class TargetObj{
        //目標(biāo)方法
          public void targetMethod(){
               System.out.println("-----目標(biāo)方法執(zhí)行----");
           }
        }
    
7.2 測(cè)試代碼
@Test
    public void aopchain() throws Throwable {
        List<MethodInterceptor> chain = Lists.newArrayList();
        //攔截器鏈,穿插這 放入 前置 和 后置 攔截器 。
        chain.add(new AfterMethodInterceptor("1"));
        chain.add(new BeforMethodInterceptor("1"));
        chain.add(new AfterMethodInterceptor("2"));
        chain.add(new BeforMethodInterceptor("2"));
        chain.add(new AfterMethodInterceptor("3"));
        chain.add(new BeforMethodInterceptor("3"));
        //目標(biāo)對(duì)象
        TargetObj targetObj = new TargetObj();
        //目標(biāo)方法
        Method method = TargetObj.class.getMethod("targetMethod");
        DefaultMethodInvacation defaultMethodInvacation = new DefaultMethodInvacation(chain, targetObj, method, null);
        //執(zhí)行攔截器鏈
        defaultMethodInvacation.process();
    }
7.3 執(zhí)行結(jié)果

雖然 前置 和 后置 都是 無(wú)序的 存放在 攔截器鏈中,但是 前置 和 后置 都在各自的位置執(zhí)行。

執(zhí)行前置通知1
執(zhí)行前置通知2
執(zhí)行前置通知3
-----目標(biāo)方法執(zhí)行----
執(zhí)行后置通知3
執(zhí)行后置通知2
執(zhí)行后置通知1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評(píng)論 19 139
  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書(shū)筆記,整理的知識(shí)點(diǎn),也是為了防止忘記,尊重勞動(dòng)成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 12,444評(píng)論 6 86
  • **** AOP 面向切面編程 底層原理 代理?。?! 今天AOP課程1、 Spring 傳統(tǒng) AOP2、 Spri...
    luweicheng24閱讀 1,506評(píng)論 0 1
  • title: Spring_AOP源碼分析date: 2016-11-03 01:15:11categories:...
    raincoffee閱讀 1,830評(píng)論 2 36
  • 本博中關(guān)于spring的文章:Spring IOC和AOP原理,Spring事務(wù)原理探究,Spring配置文件屬性...
    Maggie編程去閱讀 4,202評(píng)論 0 34

友情鏈接更多精彩內(nèi)容