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实现的另一层神秘的面纱。

相关推荐
Exclusive_Cat2 小时前
SpringMVC参数接收与数据返回详解
spring·mvc
ChinaRainbowSea3 小时前
补充:问题:CORS ,前后端访问跨域问题
java·spring boot·后端·spring
hqxstudying5 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
春生野草6 小时前
关于SpringMVC的整理
spring
Bug退退退1236 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
hello早上好8 小时前
CGLIB代理核心原理
java·spring
先睡14 小时前
Redis的缓存击穿和缓存雪崩
redis·spring·缓存
Bug退退退12318 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq
booooooty1 天前
基于Spring AI Alibaba的多智能体RAG应用
java·人工智能·spring·多智能体·rag·spring ai·ai alibaba
极光雨雨1 天前
Spring Bean 控制销毁顺序的方法总结
java·spring