Spring技术内幕:深入解析Spring架构与设计原理(第2版)
上QQ阅读APP看书,第一时间看更新

3.4 Spring AOP拦截器调用的实现

3.4.1 设计原理

在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。

如果使用JDK的Proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调;而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求,通过Dynamic-AdvisedInterceptor来完成回调。关于这两种方式的拦截过程,下面我们会进行详细的分析。

3.4.2 JdkDynamicAopProxy的invoke拦截

前面介绍了在Spring中通过ProxyFactoryBean实现AOP功能的第一步、得到AopProxy代理对象的基本过程,以及通过使用JDK和CGLIB最终产生AopProxy代理对象的实现原理。下面来看看AopProxy代理对象的拦截机制是怎样发挥作用和实现AOP功能的。在JdkDynamicAopProxy中生成Proxy对象时,我们回顾一下它的AopProxy代理对象的生成调用,如下所示:

        Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

这里的this参数对应的是InvocationHandler对象,InvocationHandler是JDK定义的反射类的一个接口,这个接口定义了invoke方法,而这个invoke方法是作为JDK Proxy代理对象进行拦截的回调入口出现的。在JdkDynamicAopProxy中实现了InvocationHandler接口,也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截或者说功能增强的工作。JdkDynamicAopProxy的invoke方法实现如代码清单3-18所示。从代码清单中可以看到,对Proxy对象的代理设置是在invoke方法中完成的,这些设置包括获取目标对象、拦截器链,同时把这些对象作为输入,创建了ReflectiveMethodInvocation对象,通过这个ReflectiveMethodInvocation对象来完成对AOP功能实现的封装。在这个invoke方法中,包含了一个完整的拦截器链对目标对象的拦截过程,比如获得拦截器链并对拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截增强,直到最后对目标对象方法的运行等。

代码清单3-18 AopProxy代理对象的回调

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodInvocation invocation = null;
            Object oldProxy = null;
            boolean setProxyContext = false;
            TargetSource targetSource = this.advised.targetSource;
            Class targetClass = null;
            Object target = null;
            try {
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                      //如果目标对象没有实现Object类的基本方法:equals
                      return equals(args[0]);
                }
                if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                      //如果目标对象没有实现Object类的基本方法:hashCode
                      return hashCode();
                }
                if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                          method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                      //根据代理对象的配置来调用服务
                      return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                  }
                  Object retVal = null;
                  if (this.advised.exposeProxy) {
                                      oldProxy = AopContext.setCurrentProxy(proxy);
                      setProxyContext = true;
                  }
                  //得到目标对象的地方
                  target = targetSource.getTarget();
                  if (target != null) {
                      targetClass = target.getClass();
                  }
                                    // 这里获得定义好的拦截器链
                  List<Object> chain = this.advised.getInterceptorsAndDynamicInterception
                  Advice(method, targetClass);
                  // 如果没有设定拦截器,那么就直接调用target的对应方法
                  if (chain.isEmpty()) {
                      retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
                  }
                  else {
                      // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法
                      //通过构造一个ReflectiveMethodInvocation来实现,下面会看
                      //这个ReflectiveMethodInvocation类的具体实现
                      invocation = new ReflectiveMethodInvocation(proxy, target, method, args,
                      targetClass, chain);
                      //沿着拦截器链继续前进
                      retVal = invocation.proceed();
                  }
                  if (retVal != null && retVal = = target && method.getReturnType().isInstance(proxy) &&
                  !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                      retVal = proxy;
                  }
                  return retVal;
              }
              finally {
                  if (target != null && !targetSource.isStatic()) {
                                      targetSource.releaseTarget(target);
                  }
                  if (setProxyContext) {
                      AopContext.setCurrentProxy(oldProxy);
                  }
              }
        }

3.4.3 Cglib2AopProxy的intercept拦截

在分析Cglib2AopProxy的AopProxy代理对象生成的时候,我们了解到对于AOP的拦截调用,其回调是在DynamicAdvisedInterceptor对象中实现的,这个回调的实现在intercept方法中,如代码清单3-19所示。Cglib2AopProxy的intercept回调方法的实现和JdkDynamic-AopProxy的回调实现是非常类似的,只是在Cglib2AopProxy中构造CglibMethodInvocation对象来完成拦截器链的调用,而在JdkDynamicAopProxy中是通过构造ReflectiveMethod-Invocation对象来完成这个功能的。

代码清单3-19 DynamicAdvisedInterceptor的intercept

        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
        methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Class targetClass = null;
            Object target = null;
            try {
                  if (this.advised.exposeProxy) {
                      oldProxy = AopContext.setCurrentProxy(proxy);
                      setProxyContext = true;
                  }
                  target = getTarget();
                  if (target != null) {
                      targetClass = target.getClass();
                  }
                  //advised中取得配置好的AOP通知
                  List<Object> chain = this.advised.getInterceptors
                  AndDynamicInterceptionAdvice(method, targetClass);
                  Object retVal = null;
                  // 如果没有AOP通知配置,那么直接调用target对象的调用方法
                  if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                      retVal = methodProxy.invoke(target, args);
                  }
                  else {
                      //通过CglibMethodInvocation来启动advice通知
                      retVal = new CglibMethodInvocation(proxy, target, method, args,
                      targetClass, chain, methodProxy).proceed();
                  }
                  retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
                  return retVal;
            }
            finally {
                  if (target != null) {
                      releaseTarget(target);
                  }
                  if (setProxyContext) {
                      AopContext.setCurrentProxy(oldProxy);
                  }
            }
        }

3.4.4 目标对象方法的调用

如果没有设置拦截器,那么会对目标对象的方法直接进行调用。对于JdkDynamic-AopProxy代理对象,这个对目标对象的方法调用是通过AopUtils使用反射机制在AopUtils.invokeJoinpointUsingReflection的方法中实现的,如代码清单3-20所示。在这个调用中,首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。

代码清单3-20 使用反射完成目标对象的方法调用

        public static Object invokeJoinpointUsingReflection(Object target, Method method,
        Object[] args)
            throws Throwable {
                      // 这里是使用反射调用target对象方法的地方
            try {
                ReflectionUtils.makeAccessible(method);
                return method.invoke(target, args);
            }
            catch (InvocationTargetException ex) {
                //抛出AOP异常,对异常进行转换
                throw ex.getTargetException();
            }
            catch (IllegalArgumentException ex) {
                throw new AopInvocationException("AOP configuration seems to be invalid:
                tried calling method [" + method + "] on target [" + target + "]", ex);
            }
            catch (IllegalAccessException ex) {
                throw new AopInvocationException("Could not access method [" + method + "]", ex);
            }
        }

对于使用Cglib2AopProxy的代理对象,它对目标对象的调用是通过CGLIB的MethodProxy对象来直接完成的,这个对象的使用是由CGLIB的设计决定的。具体的调用在DynamicAdvisedInterceptor的intercept方法中可以看到,使用的是CGLIB封装好的功能,相对JdkDynamicAopProxy的实现来说,形式上看起来较为简单,但它们的功能却是一样的,都是完成对目标对象方法的调用,具体的代码实现如下:

        retVal = methodProxy.invoke(target, args);

3.4.5 AOP拦截器链的调用

在了解了对目标对象的直接调用以后,开始进入AOP实现的核心部分了,AOP是怎样完成对目标对象的增强的?这些实现封装在AOP拦截器链中,由一个个具体的拦截器来完成。

前面介绍了使用JDK和CGLIB会生成不同的AopProxy代理对象,从而构造了不同的回调方法来启动对拦截器链的调用,比如在JdkDynamicAopProxy中的invoke方法,以及在Cglib2AopProxy中使用DynamicAdvisedInterceptor的intercept方法。虽然它们使用了不同的AopProxy代理对象,但最终对AOP拦截的处理可谓殊途同归:它们对拦截器链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现的。在proceed方法中,会逐个运行拦截器的拦截方法。在运行拦截器的拦截方法之前,需要对代理方法完成一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。大家一定还记得前面提到的,在Pointcut切点中需要进行matches的匹配过程,即matches调用对方法进行匹配判断,来决定是否需要实行通知增强。以下看到的调用就是进行matches的地方,具体的处理过程在ReflectiveMethodInvocation的proceed方法中,如代码清单3-21所示。在proceed方法中,先进行判断,如果现在已经运行到拦截器链的末尾,那么就会直接调用目标对象的实现方法;否则,沿着拦截器链继续进行,得到下一个拦截器,通过这个拦截器进行matches判断,判断是否是适用于横切增强的场合,如果是,从拦截器中得到通知器,并启动通知器的invoke方法进行切面增强。在这个过程结束以后,会迭代调用proceed方法,直到拦截器链中的拦截器都完成以上的拦截过程为止。

代码清单3-21 拦截器的运行

        public Object proceed() throws Throwable {
              //从索引为-1的拦截器开始调用,并按序递增
              //如果拦截器链中的拦截器迭代调用完毕,这里开始调用target的函数,这个函数是通过
              //反射机制完成的,具体实现在AopUtils.invokeJoinpointUsingReflection方法中
              if (this.currentInterceptorIndex == this.interceptorsAndDynamic-
              MethodMatchers.size() -1) {
                          return invokeJoinpoint();
              }
              //这里沿着定义好的 interceptorOrInterceptionAdvice链进行处理
              Object interceptorOrInterceptionAdvice =
              this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
              if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                    //这里对拦截器进行动态匹配的判断,还记得前面分析的Pointcut吗?这里是
                    //触发进行匹配的地方,如果和定义的Pointcut匹配,那么这个advice将会得到执行
                    InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                    if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                          return dm.interceptor.invoke(this);
                    }
                    else {
                          //如果不匹配,那么proceed会被递归调用,直到所有的拦截器都被运行过为止
                          return proceed();
                    }
              }
              else {
                    //如果是一个interceptor,直接调用这个interceptor对应的方法
                    return((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
              }
        }

以上就是整个拦截器及target目标对象方法被调用的过程。“小荷才露尖尖角”,我们已经在这里看到对advice通知的调用入口了,虽然这个大名鼎鼎的advice到现在还没有完全现身,但已经看到了它的运行轨迹。先提出几个问题来提提大家的兴趣:这些advisor是怎样从配置文件中获得,并配置到proxy的拦截器链中去的?我们平常使用的advice通知是怎样起作用的?这些都是了解AOP实现原理的重要问题,下面就这些问题已经展示的线索继续展开分析,去寻求这些问题的答案。

3.4.6 配置通知器

在整个AopProxy代理对象的拦截回调过程中,先回到ReflectiveMethodInvocation类的proceed方法。在这个方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下所示:

        Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

这个interceptorOrInterceptionAdvice是获得的拦截器,它通过拦截器机制对目标对象的行为增强起作用。这个拦截器来自interceptorsAndDynamicMethodMatchers,具体来说,它是interceptorsAndDynamicMethodMatchers持有的List中的一个元素。关于如何配置拦截器的问题,就转化为这个List中的拦截器元素是从哪里来,在哪里配置的问题。接着对invoke调用进行回放,回到JdkDynamicAopProxy中的invoke方法中,可以看到这个List中的interceptors是在哪个调用中获取的。对于Cglib2AopProxy,也有类似的过程,只不过这个过程是在DynamicAdvisedInterceptor的intercept回调中实现的,如下所示:

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

在上面的代码中可以看到,获取interceptors的操作是由advised对象完成的,这个advised是一个AdvisedSupport对象,从类的继承关系上看,这个AdvisedSupport类同时也是ProxyFactoryBean的基类。从AdvisedSupport的代码中可以看到getInterceptorsAnd-DynamicInterceptionAdvice的实现,如代码清单3-22所示。在这个方法中取得了拦截器链,在取得拦截器链的时候,为提高取得拦截器链的效率,还为这个拦截器链设置了缓存。

代码清单3-22 AdvisedSupport取得拦截器

        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method,
        Class targetClass) {
            //这里使用了cache,利用cache去获取已有的inteceptor链,但是第一次还是需要自己
            //动手生成的。这个inteceptor链的生成是由 advisorChainFactory完成的,
            //在这里使用的是DefaultAdvisorChainFactory
            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;
        }

取得拦截器链的工作是由配置好的advisorChainFactory来完成的,从名字上可以猜到,它是一个生成通知器链的工厂。在这里,advisorChainFactory被配置成一个DefaultAdvisorChainFactory对象,在DefaultAdvisorChainFactory中实现了interceptor链的获取过程,如代码清单3-23所示。在这个获取过程中,首先设置了一个List,其长度是由配置的通知器的个数来决定的,这个配置就是在XML中对ProxyFactoryBean做的interceptNames属性的配置。然后,DefaultAdvisorChainFactory会通过一个AdvisorAdapterRegistry来实现拦截器的注册,AdvisorAdapterRegistry对advice通知的织入功能起了很大的作用,关于AdvisorAdapterRegistry对象的实现原理,会在后面分析通知是如何实现增强的部分进行阐述。有了AdvisorAdapterRegistry注册器,利用它来对从ProxyFactoryBean配置中得到的通知进行适配,从而获得相应的拦截器,再把它加入前面设置好的List中去,完成所谓的拦截器注册过程。在拦截器适配和注册过程完成以后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intercept拦截方法取得,并启动拦截器的invoke调用,最终触发通知的切面增强。

代码清单3-23 DefaultAdvisorChainFactory生成拦截器链

        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
                Advised config, Method method, Class targetClass) {
            //advisor链已经在config中持有了,这里可以直接使用
            List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
            boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
            AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
            for (Advisor advisor : config.getAdvisors()) {
                      if (advisor instanceof PointcutAdvisor) {
                                      PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                      if (config.isPreFiltered() || pointcutAdvisor.getPointcut().
                      getClassFilter().matches(targetClass)) {
        //拦截器链是通过AdvisorAdapterRegistry来加入的,这个AdvisorAdapterRegistry
        //advice织入起了很大的作用,在后面的分析中会看到
        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                      MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
        //使用MethodMatchersmatches方法进行匹配判断
                      if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
                            if (mm.isRuntime()) {
            for (MethodInterceptor interceptor : interceptors) {
                                          interceptorList.add(new InterceptorAndDynamic
                                          MethodMatcher(interceptor, mm));
                                                  }
                                          }
                                          else {
                                                  interceptorList.addAll(Arrays.asList
                                                  (interceptors));
                                          }
                                  }
                            }
                      }
                      else if (advisor instanceof IntroductionAdvisor) {
                          IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                          if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
                          Interceptor[] interceptors = registry.getInterceptors(advisor);
                            interceptorList.addAll(Arrays.asList(interceptors));
                          }
                      }
                      else {
                          Interceptor[] interceptors = registry.getInterceptors(advisor);
                          interceptorList.addAll(Arrays.asList(interceptors));
                      }
            }
            return interceptorList;
        }
        //判断Advisors是否符合配置要求
        private static boolean hasMatchingIntroductions(Advised config, Class targetClass) {
            for (int i = 0; i < config.getAdvisors().length; i++) {
                Advisor advisor = config.getAdvisors()[i];
                if (advisor instanceof IntroductionAdvisor) {
                    IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                    if (ia.getClassFilter().matches(targetClass)) {
                        return true;
                    }
                }
            }
            return false;
        }

事实上,这里的advisor通知器是从AdvisorSupport中取得的,从对它的调用过程来看会非常清楚,如图3-16所示。

图3-16 Advisor的调用过程

在ProxyFactoryBean的getObject方法中对advisor进行初始化时,从XML配置中获取了advisor通知器。在ProxyFactoryBean中,对advisor进行初始化的代码实现如代码清单3-24所示。在这个初始化的advisor中,可以看到对IoC容器的一个getBean回调,通过对这个IoC容器的getBean调用来得到配置好的advisor通知器。

代码清单3-24 在拦截器链的初始化中获取advisor通知器

        private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
            if (this.advisorChainInitialized) {
                return;
            }
            if (!ObjectUtils.isEmpty(this.interceptorNames)) {
                if (this.beanFactory == null) {
                    throw new IllegalStateException("No BeanFactory available anymore
                    (probably due to serialization) " +
                    "- cannot resolve interceptor names " + Arrays.asList
                            (this.interceptorNames));
                }
                if (this.interceptorNames[this.interceptorNames.length -1].
                endsWith(GLOBAL_SUFFIX) &&
                this.targetName == null && this.targetSource ==
                            EMPTY_TARGET_SOURCE) {
                    throw new AopConfigException("Target required after globals");
                }
                                  for (String name : this.interceptorNames) {
                    if (logger.isTraceEnabled()) {
                          logger.trace("Configuring advisor or advice '" + name + "'");
                    }
                    if (name.endsWith(GLOBAL_SUFFIX)) {
                        if (!(this.beanFactory instanceof ListableBeanFactory)) {
                            throw new AopConfigException(
                                      "Can only use global advisors or interceptors
                                      with a ListableBeanFactory");
                        }
                        addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                        name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                    }
                    else {
                        //需要对Bean的类型进行判断,是单件类型还是prototype类型
                        Object advice;
                        if (this.singleton || this.beanFactory.isSingleton(name)) {
                        //这里是取得advisor的地方,是通过beanFactory取得的,
                        //interceptorNames这个List中的interceptor名字
                        //交给beanFactory,然后通过调用BeanFactorygetBean去获取
                          advice = this.beanFactory.getBean(name);
                        }
                          else {
                                  //如果Bean的类型是prototype类型
                                  advice = new PrototypePlaceholderAdvisor(name);
                          }
                          addAdvisorOnChainCreation(advice, name);
                    }
                }
          }
          this.advisorChainInitialized = true;
        }

advisor通知器的取得是委托给IoC容器完成的,但是在ProxyFactoryBean中是如何获得IoC容器,然后通过回调IoC容器的getBean方法来得到需要的通知器advisor的呢?这涉及IoC容器实现原理,在使用DefaultListableBeanFactory作为IoC容器的时候,它的基类是AbstractAutowireCapableBeanFactory,在这个基类中可以看到一个对Bean进行初始化的initializeBean方法。在这个Bean的初始化过程中,对IoC容器在Bean中的回调进行了设置。这个设置很简单,首先,判断这个Bean的类型是不是实现了BeanFactoryAware接口,如果是,那么它一定实现了BeanFactoryAware定义的接口方法,通过这个接口方法,可以把IoC容器设置到Bean自身定义的一个属性中去。这样,在这个Bean的自身实现中,就能够得到它所在的IoC容器,从而调用IoC容器的getBean方法,完成对IoC容器的回调,就像一个有特异功能的Bean一样,除了使用为自己设计的功能之外,还可以去调用它所在的容器的功能,如下所示:

        if (bean instanceof BeanFactoryAware) {
                    ((BeanFactoryAware) bean).setBeanFactory(this);
        }

对于IoC容器的使用,如果需要回调容器,前提是当前的Bean需要实现BeanFactory-Aware接口,这个接口只需要实现一个接口方法setBeanFactory,同时设置一个属性来持有BeanFactory的IoC容器,就可以在Bean中取得IoC容器进行回调了。在IoC容器对Bean进行初始化的时候,会对Bean的类型进行判断,如果这是一个BeanFactoryAware的Bean类型,那么IoC容器会调用这个Bean的setBeanFactory方法,完成对这个BeanFactory在Bean中的设置。具体来说,ProxyFactoryBean实现了这个接口,所以在它的初始化完成以后,可以在Bean中使用容器进行回调。这里设置的this对象,就是Bean所在的IoC容器,一般是DefaultListableBeanFactory对象。在得到这个设置好的BeanFactory以后,ProxyFactoryBean就可以通过回调容器的getBean去获取配置在Bean定义文件中的通知器了,获取通知器就是向IoC容器回调getBean的过程。了解IoC容器实现原理的读者都知道,这个getBean是IoC容器一个非常基本的方法。在调用时,ProxyFactoryBean需要给出通知器的名字,而这些名字都是在interceptorNames的List中已经配置好的,在IoC对FactoryBean进行依赖注入时,会直接注入到FactoryBean的interceptorNames的属性中。完成这个过程以后,ProxyFactoryBean就获得了配置的通知器,为完成切面增强做好准备。

3.4.7 Advice通知的实现

经过前面的分析,我们看到在AopProxy代理对象生成时,其拦截器也同样建立起来了,除此之外,我们还了解了拦截器的拦截调用和最终目标对象的方法调用的实现原理。但是,对于AOP实现的重要部分,Spring AOP定义的通知是怎样实现对目标对象的增强的呢?本小节将探讨这个问题。读者一定还记得,在为AopProxy代理对象配置拦截器的实现中,有一个取得拦截器的配置过程,这个过程是由DefaultAdvisorChainFactory实现的,而这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionAdvice方法中,有一个适配和注册过程,在这个适配和注册过程中,通过配置Spring预先设计好的拦截器,Spring加入了它对AOP实现的处理。为详细了解这个过程,先从DefaultAdvisorChainFactory的实现开始,如代码清单3-25所示。可以看到,在DefaultAdvisorChainFactory的实现中,首先构造了一个GlobalAdvisorAdapterRegistry单件,然后,对配置的Advisor通知器进行逐个遍历,这些通知器链都是配置在interceptorNames中的;从getInterceptorsAndDynamicInterceptionAdvice传递进来的advised参数对象中,可以方便地取得配置的通知器,有了这些通知器,接着就是一个由GlobalAdvisorAdapterRegistry来完成的拦截器的适配和注册过程。

代码清单3-25 DefaultAdvisorChainFactory使用GlobalAdvisorAdapterRegistry得到AOP拦截器

        //得到注册器GlobalAdvisorAdapterRegistry,这是一个单件模式的实现
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        for (Advisor advisor : config.getAdvisors()) {
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().
                getClassFilter().matches(targetClass)) {
                    //GlobalAdvisorAdapterRegistry中取得MethodInterceptor的实现
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
                            if (mm.isRuntime()) {
                    //getInterceptors()方法中创建新的对象实例
                            for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher
                            (interceptor, mm));
                                    }
                            }
                            else {
            interceptorList.addAll(Arrays.asList(interceptors));
                            }
                    }
                }
        }

仔细揣摩了以上代码的读者一定会注意到,在这个GlobalAdvisorAdapterRegistry中隐藏着不少AOP实现的重要细节,它的getInterceptors方法为AOP实现做出了很大的贡献,就是这个方法封装着advice织入实现的入口,我们先从GlobalAdvisorAdapterRegistry的实现入手,如代码清单3-26所示。从代码上看,GlobalAdvisorAdapterRegistry的实现很简洁,起到的基本上是一个适配器的作用,但同时它也是一个单件模式的应用,为Spring AOP模块提供了一个DefaultAdvisorAdapterRegistry单件,这个DefaultAdvisorAdapterRegistry是下面要分析的重点,像它的名字一样,由它来完成各种通知的适配和注册工作。

如图3-17所示为单件模式的使用,关于单件模式,可以对照Spring的源代码实现做一个了解。

图3-17 单件设计模式

代码清单3-26 GlobalAdvisorAdapterRegistry的实现

        public abstract class GlobalAdvisorAdapterRegistry {
            //单件模式的典型实现,使用静态类变量来保持一个唯一实例
            private static final AdvisorAdapterRegistry instance = new
            DefaultAdvisorAdapterRegistry();
            //返回单件DefaultAdvisorAdapterRegistry对象
            public static AdvisorAdapterRegistry getInstance() {
                  return instance;
            }
        }

从代码中可以看出,GlobalAdvisorAdapterRegistry是一个标准的单件模式的实现,它配置了一个静态的final变量instance,这个对象是在加载类的时候就生成的,而且GlobalAdvisorAdapterRegistry还是一个抽象类,不能被实例化,这样就保证了instance对象的唯一性。在使用这个instance的时候,也是通过一个静态方法getInstance()来完成的,这样就保证了这个instance唯一对象的获取。

到这里,神秘的面纱慢慢地被揭开了,在DefaultAdvisorAdapterRegistry中,设置了一系列的adapter适配器,正是这些adapter适配器的实现,为Spring AOP的advice提供编织能力。下面看一下DefaultAdvisorAdapterRegistry中究竟发生了什么,如代码清单3-27所示。首先,我们看到了一系列在AOP应用中与用到的Spring AOP的advice通知相对应的adapter适配实现,并看到了对这些adapter的具体使用。具体说来,对它们的使用主要体现在以下两个方面:一是调用adapter的support方法,通过这个方法来判断取得的advice属于什么类型的advice通知,从而根据不同的advice类型来注册不同的AdviceInterceptor,也就是前面看到的那些拦截器;另一方面,这些AdviceInterceptor都是Spring AOP框架设计好了的,是为实现不同的advice功能提供服务的。有了这些AdviceInterceptor,可以方便地使用由Spring提供的各种不同的advice来设计AOP应用。也就是说,正是这些AdviceInterceptor最终实现了advice通知在AopProxy代理对象中的织入功能。

代码清单3-27 DefaultAdvisorAdapterRegistry的实现

        public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
            //持有一个AdvisorAdapterList,这个List中的Adapter是与实现
            //Spring AOPadvice增强功能相对应的
            private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
            //这里把已有的advice实现的Adapter加入进来,有非常
            //熟悉的MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice
            //这些AOPadvice封装实现
            public DefaultAdvisorAdapterRegistry() {
                registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
                registerAdvisorAdapter(new AfterReturningAdviceAdapter());
                registerAdvisorAdapter(new ThrowsAdviceAdapter());
            }
            public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
                if (adviceObject instanceof Advisor) {
                      return (Advisor) adviceObject;
                }
                if (!(adviceObject instanceof Advice)) {
                      throw new UnknownAdviceTypeException(adviceObject);
                }
                Advice advice = (Advice) adviceObject;
                if (advice instanceof MethodInterceptor) {
                                return new DefaultPointcutAdvisor(advice);
                }
                for (AdvisorAdapter adapter : this.adapters) {
                                if (adapter.supportsAdvice(advice)) {
                            return new DefaultPointcutAdvisor(advice);
                      }
                }
                throw new UnknownAdviceTypeException(advice);
            }
            //这里是在DefaultAdvisorChainFactory中启动的getInterceptors方法
            public MethodInterceptor[] getInterceptors(Advisor advisor) throws
            UnknownAdviceTypeException {
                List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
                //Advisor通知器配置中取得advice通知
                Advice advice = advisor.getAdvice();
                //如果通知是MethodInterceptor类型的通知,直接加入interceptors
                //List中,不需要适配
                if (advice instanceof MethodInterceptor) {
                    interceptors.add((MethodInterceptor) advice);
                }
                //对通知进行适配,使用已经配置好的Adapter:MethodBeforeAdviceAdapter、
                //AfterReturningAdviceAdapter以及ThrowsAdviceAdapter,
                //然后从对应的adapter中取出封装好AOP编织功能的拦截器
                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[interceptors.size()]);
            }
            public void registerAdvisorAdapter(AdvisorAdapter adapter) {
                this.adapters.add(adapter);
            }
        }

在了解这些adapter实现之前,先复习一下adapter模式,如图3-18所示。与源代码实现进行对比,大家的理解会更加深刻,也不难在其实现中找到对应关系,从名字上就可以看到一系列的adapter,同样,adaptee就是一系列的advice。

图3-18 adapter模式

剥茧抽丝,继续看这些adapter,在DefaultAdvisorAdapterRegistry的getInterceptors调用中,从MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter以及Throws-AdviceAdapter这几个通知适配器的名字上可以看到,它们完全和advice一一对应,在这里,它们作为适配器被加入到adaper的List中。换一个角度,从这几个类的设计层次和关系上看,它们都是实现AdvisorAdapter接口的同一层次的类,只是各自承担着不同的适配任务,一对一地服务于不同的advice实现,如图3-19所示。

图3-19 AdvisorAdapter接口中类的设计层次和关系

从源代码实现的角度,这个类层次实现如图3-20所示。

图3-20 AdvisorAdapter接口及其实现

以MethodBeforeAdviceAdapter为例,它的具体实现如代码清单3-28所示。这个MethodBeforeAdviceAdapter的实现并不复杂,它实现了AdvisorAdapter的两个接口方法:一个是supportsAdvice,这个方法对advice的类型进行判断,如果advice是MethodBeforeAdvice的实例,那么返回值为true;另一个是对getInterceptor接口方法的实现,这个方法把advice通知从通知器中取出,然后创建一个MethodBeforeAdviceInterceptor对象,通过这个对象把取得的advice通知包装起来,然后返回。

代码清单3-28 MethodBeforeAdviceAdapter的实现

        class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
            public boolean supportsAdvice(Advice advice) {
                return (advice instanceof MethodBeforeAdvice);
            }
            public MethodInterceptor getInterceptor(Advisor advisor) {
                MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
                return new MethodBeforeAdviceInterceptor(advice);
            }
        }

到这里就非常清楚了,Spring AOP为了实现advice的织入,设计了特定的拦截器对这些功能进行了封装。虽然应用不会直接用到这些拦截器,但却是advice发挥作用必不可少的准备。接着这条线索,还是以MethodBeforeAdviceInterceptor为例,看看它是怎样完成advice的封装的,如代码清单3-29所示。MethodBeforeAdviceInterceptor完成的是对MethodBeforeAdvice通知的封装,可以在MethodBeforeAdviceInterceptor设计的invoke回调方法中,看到首先触发了advice的before回调,然后才是MethodInvocation的proceed方法调用。看到这里,就已经和前面在ReflectiveMethodInvocation的proceed分析中联系起来了。回忆一下,在AopProxy代理对象触发的ReflectiveMethodInvocation的proceed方法中,在取得拦截器以后,启动了对拦截器invoke方法的调用。按照AOP的配置规则,ReflectiveMethodInvocation触发的拦截器invoke方法,最终会根据不同的advice类型,触发Spring对不同的advice的拦截器封装,比如对MethodBeforeAdvice,最终会触发MethodBeforeAdviceInterceptor的invoke方法。在MethodBeforeAdviceInterceptor方法中,会先调用advice的before方法,这就是MethodBeforeAdvice所需要的对目标对象的增强效果:在方法调用之前完成通知增强。

代码清单3-29 MethodBeforeAdviceInterceptor的实现

        public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
            private MethodBeforeAdvice advice;
            //为指定的Advice创建对应的MethodBeforeAdviceInterceptor对象
            public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
                Assert.notNull(advice, "Advice must not be null");
                this.advice = advice;
            }
            //这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调
            public Object invoke(MethodInvocation mi) throws Throwable {
                this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
                return mi.proceed();
            }
        }

了解了MethodBeforeAdviceInterceptor的实现原理,对于其他的advice通知的实现也可以举一反三,比如AfterReturningAdviceInterceptor的实现,它和MethodBeforeAdviceInterceptor实现不同的地方,就是在AfterReturningAdviceInterceptor的invoke方法中,先完成了MethodInvocation的proceed调用,也就是目标对象的方法调用,然后再启动advice通知的afterReturning回调,这些实现原理在代码中可以很清楚地看到,如代码清单3-30所示。

代码清单3-30 AfterReturningAdviceInterceptor的实现

        public class AfterReturningAdviceInterceptor implements MethodInterceptor,
        AfterAdvice, Serializable {
            private final AfterReturningAdvice advice;
            //为指定的advice创建AfterReturningAdviceInterceptor 对象
            public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
                Assert.notNull(advice, "Advice must not be null");
                this.advice = advice;
            }
            public Object invoke(MethodInvocation mi) throws Throwable {
                Object retVal = mi.proceed();
                this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(),
                mi.getThis());
                return retVal;
            }
        }

ThrowsAdvice的实现,和上面两种情况非常类似,也是封装在对应的AdviceInterceptor中实现的,如代码清单3-31所示,只是相对于MethodBeforeAdvice和AfterReturningAdvice的回调方法调用,ThrowsAdvice的回调方法调用要复杂一些,它维护了一个exceptionHandlerMap来对应不同的方法调用场景,这个exceptionHandlerMap中handler的取得是与触发ThrowsAdvice增强的异常相关的。

代码清单3-31 ThrowsAdviceInterceptor的实现

        public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
            private static final String AFTER_THROWING = "afterThrowing";
            private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);
            private final Object throwsAdvice;
                private final Map<Class, Method> exceptionHandlerMap = new HashMap<Class,
                Method>();
            public ThrowsAdviceInterceptor(Object throwsAdvice) {
                Assert.notNull(throwsAdvice, "Advice must not be null");
                this.throwsAdvice = throwsAdvice;
                //配置ThrowsAdvice的回调方法
                Method[] methods = throwsAdvice.getClass().getMethods();
                for (Method method : methods) {
                    if (method.getName().equals(AFTER_THROWING) &&
                        (method.getParameterTypes().length == 1 || method.
                        getParameterTypes().length == 4) &&
                        Throwable.class.isAssignableFrom(method.getParameterTypes()
                        [method.getParameterTypes().length -1])
                        ) {
                    //配置异常处理
                this.exceptionHandlerMap.put(method.getParameterTypes()
                [method.getParameterTypes().length -1], method);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Found exception handler method: " + method);
                        }
                    }
                }
                if (this.exceptionHandlerMap.isEmpty()) {
                    throw new IllegalArgumentException(
                            "At least one handler method must be found in class [" +
                            throwsAdvice.getClass() + "]");
                }
            }
            public int getHandlerMethodCount() {
                return this.exceptionHandlerMap.size();
            }
            private Method getExceptionHandler(Throwable exception) {
                Class exceptionClass = exception.getClass();
                if (logger.isTraceEnabled()) {
                    logger.trace("Trying to find handler for exception of type [" +
                    exceptionClass.getName() + "]");
                }
                Method handler = this.exceptionHandlerMap.get(exceptionClass);
                while (handler == null && !exceptionClass.equals(Throwable.class)) {
                    exceptionClass = exceptionClass.getSuperclass();
                    handler = this.exceptionHandlerMap.get(exceptionClass);
                }
                if (handler != null && logger.isDebugEnabled()) {
                    logger.debug("Found handler for exception of type [" +
                    exceptionClass.getName() + "]: " + handler);
                }
                return handler;
            }
            public Object invoke(MethodInvocation mi) throws Throwable {
                //把对目标对象的方法调用放入try/catch中,并在catch中触发
                //ThrowsAdvice的回调,
                //把异常接着向外抛出,不做过多的处理
                try {
                    return mi.proceed();
                }
                catch (Throwable ex) {
                    Method handlerMethod = getExceptionHandler(ex);
                    if (handlerMethod != null) {
                        invokeHandlerMethod(mi, ex, handlerMethod);
                    }
                    throw ex;
                }
            }
            //通过反射启动对ThrowsAdvice回调方法的调用
            private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method)
            throws Throwable {
                Object[] handlerArgs;
                if (method.getParameterTypes().length == 1) {
                    handlerArgs = new Object[] { ex };
                }
                else {
                    handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(),
                    mi.getThis(), ex};
                }
                try {
                    method.invoke(this.throwsAdvice, handlerArgs);
                }
                catch (InvocationTargetException targetEx) {
                    throw targetEx.getTargetException();
                }
            }
        }

3.4.8 ProxyFactory实现AOP

在前面的分析中,我们了解了以ProxyFactoryBean为例Spring AOP的实现线索。回到前面提到的Spring AOP的类层次关系,从中看到,除了使用ProxyFactoryBean实现AOP应用之外,还可以使用ProxyFactory来实现Spring AOP的功能,只是在使用ProxyFactory的时候,需要编程式地完成AOP应用的设置。下面举一个使用ProxyFactory的例子,如代码清单3-32所示。

代码清单3-32 ProxyFactory的使用

        TargetImpl target = new TargetImpl();
        ProxyFactory aopFactory = new ProxyFactory(target);
        aopFactory.addAdvisor(yourAdvisor);
        aopFactory.addAdvice(yourAdvice);
        TargetImpl targetProxy = (TargetImpl)aopFactory.getProxy();

对于使用ProxyFactory实现AOP功能,其实现原理与ProxyFactoryBean的实现原理是一样的,只是在最外层的表现形式上有所不同。ProxyFactory没有使用FactoryBean的IoC封装,而是通过直接继承ProxyCreatorSupport的功能来完成AOP的属性配置。至于其他ProxyCreatorSupport的子类,ProxyFactory取得AopProxy代理对象其实是和ProxyFactoryBean一样的,一般来说,也是以getProxy为入口,由DefaultAopProxyFactory来完成的。关于取得AopProxy的详细分析和以后对拦截器调用的实现原理,前面都分析过了,这里不再重复。对ProxyFactory实现感兴趣的读者,可以从代码清单3-33中看到它与ProxyFactoryBean实现上不同的地方。从代码清单中可以看到,由ProxyFactory的getProxy方法取得AopProxy代理对象,getProxy方法的实现使用了ProxyFactory的基类ProxyCreator-Support的createProxy方法来生成AopProxy代理对象,而AopProxy代理对象的生成是由AopProxyFactory来完成的,它会生成JDK或者CGLIB的代理对象。从这里的getProxy的实现开始,ProxyFactory和ProxyFactoryBean在AOP的功能实现上,包括以后拦截器的调用等,基本上都是一样的。

代码清单3-33 ProxyFactory的实现

        public class ProxyFactory extends ProxyCreatorSupport {
            public ProxyFactory() {
            }
            public ProxyFactory(Object target) {
                  Assert.notNull(target, "Target object must not be null");
                  setInterfaces(ClassUtils.getAllInterfaces(target));
                  setTarget(target);
            }
            public ProxyFactory(Class[] proxyInterfaces) {
                  setInterfaces(proxyInterfaces);
            }
        public ProxyFactory(Class proxyInterface, Interceptor interceptor) {
                addInterface(proxyInterface);
                addAdvice(interceptor);
            }
        public ProxyFactory(Class proxyInterface, TargetSource targetSource) {
                addInterface(proxyInterface);
                setTargetSource(targetSource);
            }
            public <T> T getProxy() {
                  return (T) createAopProxy().getProxy();
            }
            public <T> T   getProxy(ClassLoader classLoader) {
                  return (T) createAopProxy().getProxy(classLoader);
            }
            public static Object getProxy(Class proxyInterface, Interceptor interceptor) {
                return new ProxyFactory(proxyInterface, interceptor).getProxy();
            }
            public static Object getProxy(Class proxyInterface, TargetSource targetSource) {
                return new ProxyFactory(proxyInterface, targetSource).getProxy();
            }
        public static Object getProxy(TargetSource targetSource) {
                if (targetSource.getTargetClass() == null) {
                    throw new IllegalArgumentException("Cannot create class proxy for
                    TargetSource with null target class");
                }
                ProxyFactory proxyFactory = new ProxyFactory();
                proxyFactory.setTargetSource(targetSource);
                proxyFactory.setProxyTargetClass(true);
                return proxyFactory.getProxy();
            }
        }