zoukankan      html  css  js  c++  java
  • Spring——AOP原理及源码五【系列完】

    前情回顾:

      上一篇中,通过 wrapIfNecessary 方法,我们获取到了合适的增强器(日志方法)与业务

    类进行包装,最终返回了我们业务类的代理对象。

      

     

      本篇我们将从业务方法的执行开始,看看增强器(日志方法)是怎么在方法执行的前后和发

    生异常时被调用的。以及在文章的最后总结整个AOP的执行流程。

     

    1、调试的起点:

    给测试方法打上断点,然后一直跳到下一个断点直到执行方法,如下  

    接着进入方法,会被intercept方法拦截 

    进入断点:

     1 @Override
     2         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
     3             Object oldProxy = null;
     4             boolean setProxyContext = false;
     5             Class<?> targetClass = null;
     6             Object target = null;
     7             try {
     8                 if (this.advised.exposeProxy) {
     9                     // Make invocation available if necessary.
    10                     oldProxy = AopContext.setCurrentProxy(proxy);
    11                     setProxyContext = true;
    12                 }
    13                 // May be null. Get as late as possible to minimize the time we
    14                 // "own" the target, in case it comes from a pool...
    15                 target = getTarget();
    16                 if (target != null) {
    17                     targetClass = target.getClass();
    18                 }
    19                 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    20                 Object retVal;
    21                 // Check whether we only have one InvokerInterceptor: that is,
    22                 // no real advice, but just reflective invocation of the target.
    23                 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
    24                     // We can skip creating a MethodInvocation: just invoke the target directly.
    25                     // Note that the final invoker must be an InvokerInterceptor, so we know
    26                     // it does nothing but a reflective operation on the target, and no hot
    27                     // swapping or fancy proxying.
    28                     Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    29                     retVal = methodProxy.invoke(target, argsToUse);
    30                 }
    31                 else {
    32                     // We need to create a method invocation...
    33                     retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    34                 }
    35                 retVal = processReturnType(proxy, target, method, retVal);
    36                 return retVal;
    37             }
    38             finally {
    39                 if (target != null) {
    40                     releaseTarget(target);
    41                 }
    42                 if (setProxyContext) {
    43                     // Restore old proxy.
    44                     AopContext.setCurrentProxy(oldProxy);
    45                 }
    46             }
    47         }
    intercept


    intercept 方法从上往下看:

    16~18:获取目标类(注意不是代理对象)

      

     

    19:通过目标类和目标方法获取拦截器链

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);


     

    2、重点探究获取拦截器链的过程

    进入 getInterceptorsAndDynamicInterceptionAdvice

     

    继续进入 this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass)

     1 @Override
     2     public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
     3             Advised config, Method method, Class<?> targetClass) {
     4 
     5         // This is somewhat tricky... We have to process introductions first,
     6         // but we need to preserve order in the ultimate list.
     7         List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
     8         Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
     9         boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    10         AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    11 
    12         for (Advisor advisor : config.getAdvisors()) {
    13             if (advisor instanceof PointcutAdvisor) {
    14                 // Add it conditionally.
    15                 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
    16                 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
    17                     MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    18                     MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
    19                     if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
    20                         if (mm.isRuntime()) {
    21                             // Creating a new object instance in the getInterceptors() method
    22                             // isn't a problem as we normally cache created chains.
    23                             for (MethodInterceptor interceptor : interceptors) {
    24                                 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
    25                             }
    26                         }
    27                         else {
    28                             interceptorList.addAll(Arrays.asList(interceptors));
    29                         }
    30                     }
    31                 }
    32             }
    33             else if (advisor instanceof IntroductionAdvisor) {
    34                 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
    35                 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
    36                     Interceptor[] interceptors = registry.getInterceptors(advisor);
    37                     interceptorList.addAll(Arrays.asList(interceptors));
    38                 }
    39             }
    40             else {
    41                 Interceptor[] interceptors = registry.getInterceptors(advisor);
    42                 interceptorList.addAll(Arrays.asList(interceptors));
    43             }
    44         }
    45 
    46         return interceptorList;
    47     }
    getInterceptorsAndDynamicInterceptionAdvice

     

    以上代码从上往下看:

    5:创建拦截器链

    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length)

    12~32:

    • 遍历所有增强器
    • 经过一系列判断,将增强器放入interceptorList中 :
    • interceptorList.addAll(Arrays.asList(interceptors))

    46:将拦截器链返回

     

    接下来将拦截器链返回,并存入缓存中

     

    最后将拦截器链返回

     

     这就是拦截器链获取的过程


     

    接下来来到 intercept 方法的真正执行部分:

    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

    通过new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy) 获取到方法拦截器链 

    一进来先调用父类方法:

     

     设置好代理对象、目标类、目标方法、拦截器链等一系列属性:

     

    接着一路返回后调用 proceed 方法进行执行:

     1 @Override
     2     public Object proceed() throws Throwable {
     3         //    We start with an index of -1 and increment early.
     4         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
     5             return invokeJoinpoint();
     6         }
     7 
     8         Object interceptorOrInterceptionAdvice =
     9                 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    10         if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    11             // Evaluate dynamic method matcher here: static part will already have
    12             // been evaluated and found to match.
    13             InterceptorAndDynamicMethodMatcher dm =
    14                     (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    15             if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    16                 return dm.interceptor.invoke(this);
    17             }
    18             else {
    19                 // Dynamic matching failed.
    20                 // Skip this interceptor and invoke the next in the chain.
    21                 return proceed();
    22             }
    23         }
    24         else {
    25             // It's an interceptor, so we just invoke it: The pointcut will have
    26             // been evaluated statically before this object was constructed.
    27             return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    28         }
    29     }
    proceed

     

    3~6:可以看到有一个从-1开始的索引,这是用来记录当前执行次数的(这里的size为5对应我们的五个增强器)

     

     

    8~9:每次从拦截器链中获取一个增强器,索引加一

    10:判断这个增强器是不是 InterceptorAndDynamicMethodMatcher 类型,我们这里判断不满足,来到了else,返回调用 invoke 方法的结果

     


     

    接下来我们进入这个执行过程

    invoke方法调用proceed方法

     

     

    来到proceed方法继续判断索引大小

     

    往下走又来到 invoke 方法,从下图可以看到当前是异常增强器的invoke()

     

    进入invoke

    先 return 调用 proceed 方法

    可以看到下图中 catch 部分,说明如果有出现异常,会在catch部分调用增强器方法,并抛出异常

     

    接下来又是调用AfterReturning的invoke过程

     

    下图可以看到又调用了proceed 

     

    中间的过程也一样,这里就不演示了

    最终我们的索引来到末尾

    整个过程开始从内到外执行日志方法

    开始调用日志方法打印:

     

     

    抛出异常

     

     

    最终拦截器链调用完毕,得到结果:

     

    以上可以看到,整个执行流程是一个递归调用的过程,对之前排好序的拦截器链,通过索引判断界限,一层一层往里调用,最终递归回来一层层执行增强器(日志方法)

     


     

     

    3、AOP总结:

    通过@EnableAspectJAutoProxy 注解,给容器中注册 AnnotationAwareAspectJAutoProxyCreator,这个组件是一个后置处理器

    会在每一个bean创建之前执行它的后置处理器方法来获取对应增强器,并获取到目标代理对象

    在执行切面方法时,通过代理对象和增强器等信息,获取到拦截器链

    拦截器链在包装处理后进入执行流程,嵌套调用后执行增强器方法

    aop uml图

    以下UML图是我对AOP的理解,如果有不对之处,欢迎大家指出

     

  • 相关阅读:
    HDOJ 1207 汉诺塔II
    [转]写代码的小女孩
    POJ Subway tree systems
    HDOJ 3555 Bomb (数位DP)
    POJ 1636 Prison rearrangement (DP)
    POJ 1015 Jury Compromise (DP)
    UVA 10003
    UVA 103 Stacking Boxes
    HDOJ 3530 Subsequence
    第三百六十二、三天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/Unicron/p/12441483.html
Copyright © 2011-2022 走看看