Spring原理【6】Spring AOP的实现(二)

Spring AOP的设计与实现

JVM的动态代理特性

前面已经介绍了横切关注点的一些概念,以及它们在Spring中的具体设计和实现。具体来说,在SpringAOP实现中,使用的核心技术是动态代理,而这种动态代理实际上是JDK的 一个特性(在JDK1.3以上的版本里,实现了动态代理模式)。通过JDK的动态代理特性,可 以为任意Java对象创建代理对象,对于具体使用来说,这个特性是通过Java Reflection API来完成的。

在JDK中,需要实现下面所示的InvocationHandler实现代理模式。

typescript 复制代码
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

在这个接口方法中,只声明了一个invoke方法,这个invoke方法的第一个参数是代理对象实例,第二个参数是Method方法对象,代表的是当前Proxy被调用的方法,最后一个参数是被调用的方法中的参数。通过这些信息,在invoke方法实现中,已经可以了解Proxy对象的调用背景了。至于怎样让invoke方法和Proxy挂上钩,熟悉Proxy用法的读者都知道,只要在实现通过调用Proxy.newIntance方法生成具体Proxy对象时把InvocationHandler设置到参数里面就可以了,剩下的由Java虚拟机来完成。

Spring AOP的应用场景

Spring AOP为IoC的使用提供了更多的便利,一方面,应用可以直接使用AOP的功能设计应用的横切关注点,把跨腾越应用程序多个模块的功能抽象出来,并通过衡单的AOP的使用,灵活地编制到模块中,比如可以通过AOP实现应用程序中的日志功能。另一方面,在Spring内部,一些支持模块也是通过SpringAOP来实现的,比如后面将要详细介绍的事务处理。从这两个角度就已经可以看到SpringAOP的核心地位了。下面以ProxyFactoryBean的实现为例,和大家一起来了解SpringAOP的具体设计和实现。

建立AopProxy代理对象

设计原理

在Spring的AOP模块中,一个主要的部分是代理对象的生成,而对于Spring应用,可以看到,是通过配置和调用Spring的ProxyFactoryBean来完成这个任务的。在ProxyFactoryBean中,封装了主要代理对象的生成过程。在这个生成过程中,可以使用JDK的Proxy和CGLIB两种生成方式。 以ProxyFactory的设计为中心,可以看到相关的类继承关系如下图所示。

在这个类继承关系中,可以看到完成AOP应用的类,比如AspectJProxyFactory、ProxyFactory和ProxyFactoryBean,它们都在同一个类的继承体系下,都是ProxyConfig、AdvisedSupport和ProxyCreatorSupport的子类。作为共同基类,可以将ProxyConfig看成是个数据基类,这个数据基类为ProxyFactoryBean这样的子类提供了配置属性,在另一个基类AdvisedSupport的实现中,封装了AOP对通知和通知器的相关操作,这些操作对于不同的AOP的代理对象的生成都是一样的,但对于具体的AOP代理对象的创建,AdvisedSupport把它交给它的子类们去完成;对于ProxyCreatorSupport,可以将它看成是其子类创建AOP代理对象的一个辅助类。通过继承以上提到的基类的功能实现,具体的AOP代理对象的生成,根据不同的需要,分别由ProxyFactoryBean、AspectJProxyFactory和ProxyFactory来完成。对于需要使用Aspecu的AOP应用,AspectJProxyFactory起到集成Spring和AspectJ的作用;对于使用SpringAOP的应用,ProxyFactoryBean和ProxyFactoy都提供了AOP功能的封装,只是使用ProxyFactoryBean,可以在IoC容器中完成声明式配置,而使用ProxyFactory,则需要编程式地使用SpringAOP的功能,对于它们是如何封装实现AOP功能的,会在本章小结中给出详细的分析,在这里,通过这些类层次关系的介绍,先给读者留下一个大致的印象。

ProxyFactoryBean的类层次关系如下:

配置ProxyFactoryBean

从这部分开始,进入到Spring AOP的实现部分,在分析Spring AOP的实现原理中,主要以ProxyFactoryBean的实现作为例子和实现的基本线索进行分析。这是因为ProxyFactoryBean是在Spring IoC环境中创建AOP应用的底层方法,也是最灵活的方法, Spring通过它完成了对AOP使用的封装。以ProxyFactoryBean的实现为入口,逐层深入,是一条帮助我们快速理解SpringAOP实现的学习路径。

在了解ProxyFactoryBean的实现之前,先简要介绍一下ProxyFactoryBean的配置和使用,在基于XML配置Spring的Bean时,往往需要一系列的配置步骤来使用ProxyFactoryBean和AOP。 1)定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义。很重要的一点是, 这个通知器的实现定义了需要对自标对象进行增强的切面行为,也就是Advice通知。 2)定义ProxyFactoryBean,把它作为另个Bean来定义,它是封装AOP功能的主要类。在配置ProxyFactoryBean时,需要设定与AOP实现相关的重要属性,比如proxyInterface、interceptorNames和target等。从属性名称可以看出,interceptorNames属性的值往往设置为需要定义的通知器,因为这些通知器在ProxyFactoryBean的AOP配置下,是通过使用代理对象的拦截器机制起作用的。所以,这依然沿用了拦截器这个名字,也算是旧瓶装新酒吧。 3)定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来 增强的对象,也就是前面提到的base对象。有了这些配置,就可以使用ProxyFactoryBean完成AOP的基本功能了。关于配置的例子如下代码所示。与前面提到的配置步骤相对应,可以看到,除定义了ProxyFactoryBear的AOP封装外,还定义了一个Advisor,名为testAdvisor。作为ProxyFactory配置的一部分,还需要配置拦截的方法调用接口和目标对象。这些基本的配置,是使用ProxyFactoryBean实现AOP功能的重要组成,其实现和作用机制也是后面重点分析的内容。

javascript 复制代码
<bean id="testAdvisor" class="com.abc.TestAdvisor"/>
<bean id="testAop" class="org.springframework.aop.ProxyFactoryBean>
<property name="proxyInterfaces"><value>com.test.AbcInterface"</value></property>
<property name="target">
   <bean class="com.abc.TestTarget"/>
</property>
<property name="interceptorNames">
   <list><value>testAdvisor</value></iist>
</property>
</bean>

掌握这些配置后,就可以具体看一看这些AOP是如何实现的,也就是说,切面应用是怎样通过ProxyFactoryBean对target对象起作用的,下面我们会详细地分析这个部分。

ProxyFactoryBean生成AopProxy代理对象

在SpringAOP的使用中,我们已经了解到,可以通过ProxyFactoryBean来配置目标对象和切面行为。这个ProxyFactoryBean是一个FactoryBean,对FactoryBean这种Spring应用中经常出现的Bean的工作形式,大家一定不会感到陌生,对于FactoryBean的工作原理,已经在结合IoC容器的实现原理分析中做过阐述。在ProxyFactoryBean中,通过interceptorNames属性来配置已经定义好的通知器Advisor。虽然名字为interceptorNames,但实际上却是供AOP应用配置通知器的地方。在ProxyFactoryBean中,需要为target目标对象生成Proxy代理对象,从而为AOP横切面的编织做好准备工作。这些具体的代理对象生成工作,在以后的实现原理分析中,我们可以看到是通过JDK的Proxy或CGLIB来完成的。 ProxyFactoryBean的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象,是以getObjectO方法作为入口完成的;ProxyFactoryBean实现中的getObject方法,是FactoryBean需要实现的接口。对ProxyFactoryBean来说,把需要对target目标对象增加的增强处理,都通过getObject方法进行封装了,这些增强处理是为AOP功能的实现提供服务的。getObject的实现如下代码所示。getObject方法首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器都要从配置中读取,然后为代理对象的生成做好准备。在生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的Bean,所以要对代理对象的生成做一个区分。

kotlin 复制代码
public Object getObject() throws BeansException {
   initializeAdvisorChain();
   if (isSingleton()) {
      return getSingletonInstance();
   }
   else {
      if (this.targetName == null) {
         logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
               "Enable prototype proxies by setting the 'targetName' property.");
      }
      return newPrototypeInstance();
   }
}

为Proxy代理对象配置Advisor链是在initializeAdvisorChain方法中完成的,如下代码所示。这个初始化过程有一个标志位advisorChainInitialized,这个标志用来表示通知器链是否已经初始化。如果已经初始化,那么这里就不会再初始化,而是直接返回。也就是说,这个初始化的工作发生在应用第一次通过ProxyFactoryBean去获取代理对象的时候。在完成这个初始化之后,接着会读取配置中出现的所有通知器,这个取得通知器的过程也比较简单,把通知器的名字交给容器的getBean方法就可以了,这是通过对IoC容器实现的一个回调来完成的。然后把从IoC容器中取得的通知器加入拦截器链中,这个动作是由addAdvisorOnChainCreation方法来实现的。

kotlin 复制代码
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
   if (!this.advisorChainInitialized && !ObjectUtils.isEmpty(this.interceptorNames)) {
      if (this.beanFactory == null) {
         throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
               "- cannot resolve interceptor names " + Arrays.toString(this.interceptorNames));
      }

      // Globals can't be last unless we specified a targetSource using the property...
      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");
      }

      // 这里是添加Advisor链的调用,是通过interceptorNames属性进行配置的
      for (String name : this.interceptorNames) {
         if (name.endsWith(GLOBAL_SUFFIX)) {
            if (!(this.beanFactory instanceof ListableBeanFactory)) {
               throw new AopConfigException(
                     "Can only use global advisors or interceptors with a ListableBeanFactory");
            }
            addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
                  name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
         }

         else {
            // 如果程序在这里被调用,那么需要加入命名的拦截器advice,并且需要检查这个Bean是singleton还是prototype类型
            Object advice;
            // 如果是singleton类型bean
            if (this.singleton || this.beanFactory.isSingleton(name)) {
               // Add the real Advisor/Advice to the chain.
               advice = this.beanFactory.getBean(name);
            }
            else {
               // It's a prototype Advice or Advisor: replace with a prototype.
               // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
               advice = new PrototypePlaceholderAdvisor(name);
            }
            addAdvisorOnChainCreation(advice);
         }
      }

      this.advisorChainInitialized = true;
   }
}

生成singleton的代理对象在getSingletonInstance的代码中完成,这个方法是ProxyFactoryBean生成AopProxy代理对象的调用人口。代理对象会封装对target目标对象的调用,也就是说针对target对象的方法调用行为会被这里生成的代理对象所拦截。具体的生成过程是,首先读取ProxyFactoryBean中的配置,为生成代理对象做好必要的准备,比如设置代理的方法调用接口等。Spring通过AopProxy类来具体生成代理对象。对于getSingletonlnstance()方法中代理对象的生成过程,如下代码所示。

kotlin 复制代码
private synchronized Object getSingletonInstance() {
   if (this.singletonInstance == null) {
      this.targetSource = freshTargetSource();
      if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
         // 根据AOP框架来判断需要代理的接口
         Class<?> targetClass = getTargetClass();
         if (targetClass == null) {
            throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
         }
         // 设置需要代理的接口
         setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
      }
      // Initialize the shared singleton instance.
      super.setFrozen(this.freezeProxy);
      // 使用ProxyFactory来生成需要的Proxy
      this.singletonInstance = getProxy(createAopProxy());
   }
   return this.singletonInstance;
}

protected Object getProxy(AopProxy aopProxy) {
   return aopProxy.getProxy(this.proxyClassLoader);
}

这里出现了AopProxy类型的对象,Spring利用这个AopProxy接口类把AOP代理对象的实现与框架的其他部分有效地分离开来。AopProxy是一个接口,它由两个子类实现,一个是Cglib2AopProxy,另一个是JdkDynamicProxy。顾名思义,对这两个AopProxy接口的子类的实现,Spring分别通过CGLIB和JDK来生成需要的Proxy代理对象。

具体的代理对象的生成,是在ProxyFactoryBean的基类AdvisedSupport的实现中借助AopProxyFactory完成的,这个代理对象要么从JDK中生成,要么借助CGLIB获得。因为ProxyFactoryBean本身就是AdvisedSupport的子类,所以在ProxyFactoryBean中获得AopProxy是很方便的,可以在ProxyCreatorSupport中看到,具体的AopProxy是通过AopProxyFactory来生成的。至于需要生成什么样的代理对象,所有信息都封装在AdvisedSupport里,这个对象也是生成AopProxy的方法的输入参数,这里设置为this本身因为ProxyCreatorSupport本身就是AdvisedSupport的子类。在ProxyCreatorSupport中生成代理对象的入口实现,如下代码所示。

kotlin 复制代码
protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   // 通过AopProxyFactoy取得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
   return getAopProxyFactory().createAopProxy(this);
}

这里使用了AopProxyFactory来创建AopProxy,AopProxyFactory使用的是DefaultAopProxyFactory。这个被使用的AopProxyFactory,作为AopProxy的创建工厂对象,是在ProxyFactoryBean的基类ProxyCreatorSupport中被创建的。在创建AopProxyFactory时,它被设置为DefaultAopProxyFactory,很显然,Spring给出了这个默认的AopProxyFactory工厂的实现。有了这个AopProxyFactory对象以后,问题就转换为在DefaultAopProxyFactory中,AopProxy是怎样生成的了。

关于AopProxy代理对象的生成,需要考虑使用哪种生成方式,如果目标对象是接口类,那么适合使用JDK来生成代理对象,否则Spring会便用CGLIB来生成自标对象的代理对象。为了满足不同的代理对象生成的要求,DefaultAopProxyFactory作为AopProxy对象的生产工厂,可以根据不同的需要生成这两种AopProxy对象。对于AopProxy对象的生产过程,在DefaultAopProxyFactory创建AopProxy的过程中可以清楚地看到,但这是一个比较高层次的AopProxy代理对象的生成过程,如下代码清单所示。所谓高层次,是指在DefaultAopProxyFactory创建AopProxy的过程中,对不同的AopProxy代理对象的生成所涉及的生成策略和场景做了相应的设计,但是对于具体的AopProxy代理对象的生成,最终并没有由DefaultAopProxyFactory来完成,比如对JDK和CGLIE这些具体的技术的使用,对具体的实现层次的代理对象的生成,是由Spring封装的JdkDynamicAopProxy和CglibProxyFactory类来完成的。

arduino 复制代码
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (!NativeDetector.inNativeImage() &&
         (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生成Proxy
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
         
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

在AopProxy代理对象的生成过程中,首先要从AdvisedSupport对象中取得配置的自标对象,这个目标对象是实现AOP功能所必需的,道理很简单,AOP完成的是切面应用对目标对象的增强,皮之不存,毛将為附,这个目标对象可以看做是"皮",而AOP切面增强就是依附于这块皮上的"毛"。如果这里没有配置目标对象,会直接抛出异常,提醒AOP应用,需要提供正确的目标对象的配置。在对自标对象配置的检查完成以后,需要根据配置的情况来决定使用什么方式来创建AopProxy代理对象,一般而言,默认的方式是使用JDK来产生AopProxy代理对象,但是如果遇到配置的自标对象不是接口类的实现,会使用CGLIB来产生AopProxy代理对象:在便用CGLIB来产生AopProxy代理对象时,因为CGLIB是一个第二方的类库,本身不在JDK的基本类库中,所以需要在CLASSPATH路径中进行正确的配置,以便能够加载和使用。在Spring中,使用JDK和CGLIB来生成AopProxy代理对象的工作,是由JdkDynamicAopProxy和CglibProxyFactory来完成的。详细的代理对象的生成过程会在下面的小节进行详细的分析。

JDK生成AopProxy代理对象

前面介绍的ProxyFactoryBean在AopProxy代理对象和loC容器配置之间起到厂桥染的作用,这个桥染作用体现在它为代理对象的最终生成做好了准备。AopProxy代理对象可以由JDK或CGLIB来生成,而JdkDynamicAopProxy和Cglib2AopProxy实现的都是通过AopProxy接口。 在这里可以看到使用两种代理对象的实现方式,一种是使用CGLIB,另一种使用JDK自己的Proxy。具体怎样生成代理对象,通过这两个类的源代码实现就可以了解,在AopProxy的接口下,设计了Cglib2AopProxy和JdkDynamicAopProxy两种Proxy代理对象的实现,而AopProxy的接口设计也很简单,就是获得Proxy代理对象。获得Proxy代理对象的方式有两种,一种方式是需要指定ClassLoader,另一种方式则不需要指定。

先看看在AopProxy接口实现中,JdkDynamicAopProxy是怎样完成AopProxy代理对象生成工作的,这个代理对象的生成过程如下代码所示。在JdkDynamicAopProxy中,使用了JDK的Proxy类来生成代理对象,在生成Proxy对象之前,首先需要从advised对象中取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法,最终得到对应的Proxy代理对象。在生成代理对象时,需要指明三个参数,一个是类装载器,一个是代理接口,另外一个就是Proxy回调方法所在的对象,这个对象需要实现InvocationHandler接口。这个InvocationHandler接口定义了invoke方法,提供代理对象的回调入口。对于JdkDynamicAopProxy,它本身实现了InvocationHandler接口和invoke方法,这个invoke方法是Proxy代理对象的回调方法,所以可以使用this来把JdkDynamicAopProxy指派给Proxy对象,也就是说JdkDynamicAopProxy对象本身,在Proxy代理的接口方法被调用时,会触发invoke方法的回调,这个回调方法完成了AOP编织实现的封装。在这里先重点关注AopProxy代理对象的生成,Proxy代理对象的invoke实现,将是详细分析AOP实现原理的重要部分。

less 复制代码
@Override
public Object getProxy() {
   return getProxy(ClassUtils.getDefaultClassLoader());
}

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   // JDK的方法
   return Proxy.newProxyInstance(determineClassLoader(classLoader), this.proxiedInterfaces, this);
}

CGLIB生成AopProxy代理对象

在AopProxy接口实现中,可以看到使用CGLIB来生成Proxy代理对象,这个Proxy代理对象的生成可以在CglibAopProxy的代码实现中看到,同样是在AopProxy的接口方法getProxy的实现中完成的,如下代码所示。

org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)的实现如下:

scss 复制代码
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isTraceEnabled()) {
       logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
    }
​
    try {
       // 取出需要代理的target对象的Class类型
       Class<?> rootClass = this.advised.getTargetClass();
       Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
​
       Class<?> proxySuperClass = rootClass;
       if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
          proxySuperClass = rootClass.getSuperclass();
          Class<?>[] additionalInterfaces = rootClass.getInterfaces();
          for (Class<?> additionalInterface : additionalInterfaces) {
             this.advised.addInterface(additionalInterface);
          }
       }
​
       // Validate the class, writing log messages as necessary.
       validateClassIfNecessary(proxySuperClass, classLoader);
​
       // 创建并配置CGLIB的Enhancer,这个Enhancer对象是CGLIB的主要操作类
       Enhancer enhancer = createEnhancer();
       if (classLoader != null) {
          enhancer.setClassLoader(classLoader);
          if (classLoader instanceof SmartClassLoader &&
                ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
             enhancer.setUseCache(false);
          }
       }
       // 设置Enhancer对象,包括设置代理接口,回调方法,来自adviced的IOC设置,比如
       enhancer.setSuperclass(proxySuperClass);
       enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
       enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
       enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
​
       Callback[] callbacks = getCallbacks(rootClass);
       Class<?>[] types = new Class<?>[callbacks.length];
       for (int x = 0; x < types.length; x++) {
          types[x] = callbacks[x].getClass();
       }
       // fixedInterceptorMap only populated at this point, after getCallbacks call above
       enhancer.setCallbackFilter(new ProxyCallbackFilter(
             this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
       enhancer.setCallbackTypes(types);
​
       // Generate the proxy class and create a proxy instance. 通过Enhancer生成代理对象
       return createProxyClassAndInstance(enhancer, callbacks);
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
       throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
             ": Common causes of this problem include using a final class or a non-visible class",
             ex);
    }
    catch (Throwable ex) {
       // TargetSource.getTarget() failed
       throw new AopConfigException("Unexpected AOP exception", ex);
    }
}
kotlin 复制代码
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    enhancer.setInterceptDuringConstruction(false);
    enhancer.setCallbacks(callbacks);
    // 使用Enhancer生成代理对象
    return (this.constructorArgs != null && this.constructorArgTypes != null ?
          enhancer.create(this.constructorArgTypes, this.constructorArgs) :
          enhancer.create());
}
scss 复制代码
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // Parameters used for optimization choices...
    boolean isFrozen = this.advised.isFrozen();
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isStatic = this.advised.getTargetSource().isStatic();
​
    // Choose an "aop" interceptor (used for AOP calls).
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
​
    // Choose a "straight to target" interceptor. (used for calls that are
    // unadvised but can return this). May be required to expose the proxy.
    // 使用哪一种拦截器,拦截器中包含对于AOP功能的支持
    Callback targetInterceptor;
    if (exposeProxy) {
       targetInterceptor = (isStatic ?
             new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
             new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
    }
    else {
       targetInterceptor = (isStatic ?
             new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
             new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
    }
​
    // Choose a "direct to target" dispatcher (used for
    // unadvised calls to static targets that cannot return this).
    Callback targetDispatcher = (isStatic ?
          new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
​
    Callback[] mainCallbacks = new Callback[] {
          aopInterceptor,  // for normal advice
          targetInterceptor,  // invoke target without considering advice, if optimized
          new SerializableNoOp(),  // no override for methods mapped to this
          targetDispatcher, this.advisedDispatcher,
          new EqualsInterceptor(this.advised),
          new HashCodeInterceptor(this.advised)
    };
​
    Callback[] callbacks;
​
    // If the target is a static one and the advice chain is frozen,
    // then we can make some optimizations by sending the AOP calls
    // direct to the target using the fixed chain for that method.
    if (isStatic && isFrozen) {
       Method[] methods = rootClass.getMethods();
       Callback[] fixedCallbacks = new Callback[methods.length];
       this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);
​
       // TODO: small memory optimization here (can skip creation for methods with no advice)
       for (int x = 0; x < methods.length; x++) {
          Method method = methods[x];
          List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
          fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
          this.fixedInterceptorMap.put(method, x);
       }
​
       // Now copy both the callbacks from mainCallbacks
       // and fixedCallbacks into the callbacks array.
       callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
       System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
       System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
       this.fixedInterceptorOffset = mainCallbacks.length;
    }
    else {
       callbacks = mainCallbacks;
    }
    return callbacks;
}

org.springframework.aop.framework.CglibAopProxy中定义的内部类的实现如下:

kotlin 复制代码
/**
 * Method interceptor used for static targets with no advice chain. The call is
 * passed directly back to the target. Used when the proxy needs to be exposed
 * and it can't be determined that the method won't return {@code this}.
 */
// 对于静态目标的处理,没有advice逻辑链,所有处理直接放通
private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable {
​
    @Nullable
    private final Object target;
​
    public StaticUnadvisedInterceptor(@Nullable Object target) {
       this.target = target;
    }
​
    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       Object retVal = invokeMethod(this.target, method, args, methodProxy);
       return processReturnType(proxy, this.target, method, retVal);
    }
}
​
​
/**
 * Method interceptor used for static targets with no advice chain, when the
 * proxy is to be exposed.
 */
// 静态方法的处理,直接处理,用于需要暴露的代理对象,应用于事务场景
private static class StaticUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {
​
    @Nullable
    private final Object target;
​
    public StaticUnadvisedExposedInterceptor(@Nullable Object target) {
       this.target = target;
    }
​
    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       Object oldProxy = null;
       try {
          oldProxy = AopContext.setCurrentProxy(proxy);
          Object retVal = invokeMethod(this.target, method, args, methodProxy);
          return processReturnType(proxy, this.target, method, retVal);
       }
       finally {
          AopContext.setCurrentProxy(oldProxy);
       }
    }
}
​
​
/**
 * Interceptor used to invoke a dynamic target without creating a method
 * invocation or evaluating an advice chain. (We know there was no advice
 * for this method.)
 */
// 用于处理代理对象,代理对象需要处理对应的advice逻辑链
private static class DynamicUnadvisedInterceptor implements MethodInterceptor, Serializable {
​
    private final TargetSource targetSource;
​
    public DynamicUnadvisedInterceptor(TargetSource targetSource) {
       this.targetSource = targetSource;
    }
​
    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       Object target = this.targetSource.getTarget();
       try {
          Object retVal = invokeMethod(target, method, args, methodProxy);
          return processReturnType(proxy, target, method, retVal);
       }
       finally {
          if (target != null) {
             this.targetSource.releaseTarget(target);
          }
       }
    }
}
​
​
/**
 * Interceptor for unadvised dynamic targets when the proxy needs exposing.
 */
// 没有advice逻辑链的代理对象,需要暴露代理对象
private static class DynamicUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {
​
    private final TargetSource targetSource;
​
    public DynamicUnadvisedExposedInterceptor(TargetSource targetSource) {
       this.targetSource = targetSource;
    }
​
    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       Object oldProxy = null;
       Object target = this.targetSource.getTarget();
       try {
          oldProxy = AopContext.setCurrentProxy(proxy);
          Object retVal = invokeMethod(target, method, args, methodProxy);
          return processReturnType(proxy, target, method, retVal);
       }
       finally {
          AopContext.setCurrentProxy(oldProxy);
          if (target != null) {
             this.targetSource.releaseTarget(target);
          }
       }
    }
}

org.springframework.aop.framework.AopContext#setCurrentProxy的实现如下:

less 复制代码
static Object setCurrentProxy(@Nullable Object proxy) {
    // currentProxy是一个ThreadLocal对象
    Object old = currentProxy.get();
    if (proxy != null) {
       currentProxy.set(proxy);
    }
    else {
       currentProxy.remove();
    }
    return old;
}

setCurrentProxy将当前currentProxy包含的对象返回,将传入的proxy对象放入currentProxy中,实现处理过程中将代理对象暴露出去的目的。

在代码清单中,可以看到具体对CGLIB的使用,比如对Enhancer对象的配置,以及通过Enhancer对象生成代理对象的过程。在这个生成代理对象的过程中,需要注意的是对Enhancer对象callback回调的设置,正是这些回调封装了Spring AOP的实现,就像前面介绍的JDK的Proxy对象的invoke回调方法一样。在Enhancer的callback回调设置中,实际上是通过设置DynamicAdvisedInterceptor拦截器来完成AOP功能的,可以在getCallbacks方法实现中看到回调DynamicAdvisedInterceptor的设置。

这样,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy代理对象。在ProxyFactoryBean中配置的target目标对象,这时已经不会让应用直接调用其方法实现,而是作为AOP实现的一部分。对target目标对象的方法调用会首先被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。例如,对于JDK的AopProxy代理对象,使用的是InvocationHandler的invoke回调人口,而对于CGLIB的AopProxy代理对象,使用的是设置好的callback回调,这是由对CGLIB的使用来决定的。在这些callback回调中,对于AOP实现,是通过DynamicAdvisedInterceptor来完成的,而DynamicAdvisedInterceptor的回调人口是intercept方法。通过这一系列的准备,已经为实现AOP的横切机制奠定了基础,在这个基础上,AOP的Advisor已经可以通过AopProxy代理对象的拦截机制,对需要它进行增强的target目标对象发挥切面的强大威力了。

可以把AOP的实现部分看成由基础设施准备和AOP运行辅助这两个部分组成,这里的AopProxy代理对象的生成,可以看成是一个静态的AOP基础设施的建立过程。通过这个准备过程,把代理对象、挡拦截器这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。对于应用触发的AOP应用,会涉及AOP框架的运行和对AOP基础设施的使用。这些动态的运行部分,是从前面提到的拦截器回调人口开始的,这些拦截器调用的实现原理和AopProxy代理对象生成一样,也是AOP实现的重要组成部分,同时也是下面要重点分析的内容,让我们继续深入AopProxy代理对象的回调实现中去,慢慢地揭开SpringAOP实现的另一层神秘的面纱。

相关推荐
钱多多_qdd23 分钟前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
程序猿进阶2 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭11 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
李小白6611 小时前
Spring MVC(上)
java·spring·mvc
Lojarro14 小时前
【Spring】Spring框架之-AOP
java·mysql·spring
zjw_rp14 小时前
Spring-AOP
java·后端·spring·spring-aop
撒呼呼17 小时前
# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
数据库·spring boot·spring·mvc·springboot
天使day18 小时前
SpringMVC
java·spring·java-ee
壹佰大多20 小时前
【spring-cloud-gateway总结】
java·spring·gateway