源码学习之AOP-代理对象的生成

Posted 刘老c

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码学习之AOP-代理对象的生成相关的知识,希望对你有一定的参考价值。

在Spring AOP中,创建代理对象是很重要的一部分内容,还记得之前写的代理模式的那篇文章么,在那个里面,我们封装了一个getProxy()方法,用来返回生成的代理对象,其实这个就是模仿的Spring的写法,Spring通过AopProxy提供接口方法getProxy()用来获取代理对象,具体的实现则是交由自己的子类实现。


AopProxy

    我们先来认识一下AopProxy:

AopProxy:

/**
* Delegate interface for a configured AOP proxy, allowing for the creation
* of actual proxy objects.
*
* <p>Out-of-the-box implementations are available for JDK dynamic proxies
* and for CGLIB proxies, as applied by {@link DefaultAopProxyFactory}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see DefaultAopProxyFactory
*/
public interface AopProxy {

  /**
   * Create a new proxy object.
   * <p>Uses the AopProxy's default class loader (if necessary for proxy creation):
   * usually, the thread context class loader.
   * @return the new proxy object (never {@code null})
   * @see Thread#getContextClassLoader()
   */
  Object getProxy();

  /**
   * Create a new proxy object.
   * <p>Uses the given class loader (if necessary for proxy creation).
   * {@code null} will simply be passed down and thus lead to the low-level
   * proxy facility's default, which is usually different from the default chosen
   * by the AopProxy implementation's {@link #getProxy()} method.
   * @param classLoader the class loader to create the proxy with
   * (or {@code null} for the low-level proxy facility's default)
   * @return the new proxy object (never {@code null})
   */
  Object getProxy(ClassLoader classLoader);

}


    Spring 通过AopProxy接口,它通过getProxy()用来提供代理对象,他有两个子类,对应通过JDK和CGLIB生成的代理对象:


JdkDynamicAopProxy

    简单回顾一下,在之前代理模式中,我们的jdk动态代理的实现主要是通过实现InvocationHandler,代理对象的获取则是通过Proxy.new ProxyInstance(ClassLoader,Interface,InvocationHandler)完成,现在我们看下Spring中的实现:

JdkDynamicAopProxy

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//省略部分代码
  @Override
  public Object getProxy() {
     return getProxy(ClassUtils.getDefaultClassLoader());
  }

  @Override
  public Object getProxy(ClassLoader classLoader) {
     if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
     }
     Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  }

}


    可以看到,在获取代理对象这部分,Spring的实现过程也是类似的,通过调用Proxy的newProxyInstance方法,获取对应的代理对象。三个参数:一个是类加载器,一个是代理接口,还有一个就是实现了InvocationHandler接口的对象作为回调入口。


CglibAopProxy

    在代理模式中,我们cglib动态代理的代理对象是通过Enhancer对象返回的,当时我们设置了它的两个属性:enhancer.setSuperClass(),enhancer.setCallBack(),前者用来设置代理目标,后者用来设置回调,也就是设置拦截器,我们看下Spring中的cglib动态代理对象是怎么获取的:

CglibAopProxy:

@Override
public Object getProxy(ClassLoader classLoader) {
  if (logger.isDebugEnabled()) {
     logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
  }

  try {
     Class<?> rootClass = this.advised.getTargetClass();
     Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

     Class<?> proxySuperClass = rootClass;
     if (ClassUtils.isCglibProxyClass(rootClass)) {
        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);

     // Configure CGLIB Enhancer...
     Enhancer enhancer = createEnhancer();
     if (classLoader != null) {
        enhancer.setClassLoader(classLoader);
        if (classLoader instanceof SmartClassLoader &&
              ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
           enhancer.setUseCache(false);
        }
     }
     enhancer.setSuperclass(proxySuperClass);
     enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
     enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
     enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(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.
     return createProxyClassAndInstance(enhancer, callbacks);
  }


Enhancer对象是cglib中的主要操作类,我们通过它来返回代理对象,在之前的代理模式中,我们只使用到了enhancer.setsuperclass()和enhancer.setCallBack()这两个属性,前者用来设置目标对象,后者用来设置回调入口,最后通过enhancer.create()返回代理对象。

    在CglibAopProxy中,同样使用的是enhancer对象,只不过spring中设置的属性更加完善:

    比如通过enhancer.setCallbacks()添加了多个拦截器,

    又通过enhancer.setCallBackFilter()对具体使用的拦截器做了处理。

    最后还是通过enhancer.create()返回代理对象。


CallbackFilter

    这里简单的说明下CallbackFilter这个接口,通过实现这个接口重写其中的accept()方法,可以根据场景选择对应的拦截器来处理,返回的int值是回调方法中的序值:

/**
* CallbackFilter to assign Callbacks to methods.
*/
private static class ProxyCallbackFilter implements CallbackFilter {

  private final AdvisedSupport advised;

  private final Map<String, Integer> fixedInterceptorMap;

  private final int fixedInterceptorOffset;

  public ProxyCallbackFilter(AdvisedSupport advised, Map<String, Integer> fixedInterceptorMap, int fixedInterceptorOffset) {
     this.advised = advised;
     this.fixedInterceptorMap = fixedInterceptorMap;
     this.fixedInterceptorOffset = fixedInterceptorOffset;
  }

  /**
   * Implementation of CallbackFilter.accept() to return the index of the
   * callback we need.
   * <p>The callbacks for each proxy are built up of a set of fixed callbacks
   * for general use and then a set of callbacks that are specific to a method
   * for use on static targets with a fixed advice chain.
   * <p>The callback used is determined thus:
   * <dl>
   * <dt>For exposed proxies</dt>
   * <dd>Exposing the proxy requires code to execute before and after the
   * method/chain invocation. This means we must use
   * DynamicAdvisedInterceptor, since all other interceptors can avoid the
   * need for a try/catch block</dd>
   * <dt>For Object.finalize():</dt>
   * <dd>No override for this method is used.</dd>
   * <dt>For equals():</dt>
   * <dd>The EqualsInterceptor is used to redirect equals() calls to a
   * special handler to this proxy.</dd>
   * <dt>For methods on the Advised class:</dt>
   * <dd>the AdvisedDispatcher is used to dispatch the call directly to
   * the target</dd>
   * <dt>For advised methods:</dt>
   * <dd>If the target is static and the advice chain is frozen then a
   * FixedChainStaticTargetInterceptor specific to the method is used to
   * invoke the advice chain. Otherwise a DyanmicAdvisedInterceptor is
   * used.</dd>
   * <dt>For non-advised methods:</dt>
   * <dd>Where it can be determined that the method will not return {@code this}
   * or when {@code ProxyFactory.getExposeProxy()} returns {@code false},
   * then a Dispatcher is used. For static targets, the StaticDispatcher is used;
   * and for dynamic targets, a DynamicUnadvisedInterceptor is used.
   * If it possible for the method to return {@code this} then a
   * StaticUnadvisedInterceptor is used for static targets - the
   * DynamicUnadvisedInterceptor already considers this.</dd>
   * </dl>
   */
  @Override
  public int accept(Method method) {
     if (AopUtils.isFinalizeMethod(method)) {
        logger.debug("Found finalize() method - using NO_OVERRIDE");
        return NO_OVERRIDE;
     }
     if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
           method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        if (logger.isDebugEnabled()) {
           logger.debug("Method is declared on Advised interface: " + method);
        }
        return DISPATCH_ADVISED;
     }
     // We must always proxy equals, to direct calls to this.
     if (AopUtils.isEqualsMethod(method)) {
        logger.debug("Found 'equals' method: " + method);
        return INVOKE_EQUALS;
     }
     // We must always calculate hashCode based on the proxy.
     if (AopUtils.isHashCodeMethod(method)) {
        logger.debug("Found 'hashCode' method: " + method);
        return INVOKE_HASHCODE;
     }
     Class<?> targetClass = this.advised.getTargetClass();
     // Proxy is not yet available, but that shouldn't matter.
     List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
     boolean haveAdvice = !chain.isEmpty();
     boolean exposeProxy = this.advised.isExposeProxy();
     boolean isStatic = this.advised.getTargetSource().isStatic();
     boolean isFrozen = this.advised.isFrozen();
     if (haveAdvice || !isFrozen) {
        // If exposing the proxy, then AOP_PROXY must be used.
        if (exposeProxy) {
           if (logger.isDebugEnabled()) {
              logger.debug("Must expose proxy on advised method: " + method);
           }
           return AOP_PROXY;
        }
        String key = method.toString();
        // Check to see if we have fixed interceptor to serve this method.
        // Else use the AOP_PROXY.
        if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
           if (logger.isDebugEnabled()) {
              logger.debug("Method has advice and optimisations are enabled: " + method);
           }
           // We know that we are optimising so we can use the FixedStaticChainInterceptors.
           int index = this.fixedInterceptorMap.get(key);
           return (index + this.fixedInterceptorOffset);
        }
        else {
           if (logger.isDebugEnabled()) {
              logger.debug("Unable to apply any optimisations to advised method: " + method);
           }
           return AOP_PROXY;
        }
     }
     else {
        // See if the return type of the method is outside the class hierarchy
        // of the target type. If so we know it never needs to have return type
        // massage and can use a dispatcher.
        // If the proxy is being exposed, then must use the interceptor the
        // correct one is already configured. If the target is not static, then
        // cannot use a dispatcher because the target cannot be released.
        if (exposeProxy || !isStatic) {
           return INVOKE_TARGET;
        }
        Class<?> returnType = method.getReturnType();
        if (targetClass == returnType) {
           if (logger.isDebugEnabled()) {
              logger.debug("Method " + method +
                    "has return type same as target type (may return this) - using INVOKE_TARGET");
           }
           return INVOKE_TARGET;
        }
        else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
           if (logger.isDebugEnabled()) {
              logger.debug("Method " + method +
                    " has return type that ensures this cannot be returned- using DISPATCH_TARGET");
           }
           return DISPATCH_TARGET;
        }
        else {
           if (logger.isDebugEnabled()) {
              logger.debug("Method " + method +
                    "has return type that is assignable from the target type (may return this) - " +
                    "using INVOKE_TARGET");
           }
           return INVOKE_TARGET;
        }
     }
  }





ProxyFactoryBean

    上面介绍了ProcyFactory获取代理对象的主要逻辑,在介绍引介增强时,我们还使用到了ProxyFactoryBean,这里我们来看下ProxyFactoryBean里面的处理逻辑。

    ProxyFactoryBean实现了FactoryBean,是一个工厂bean,工厂bean获取对象的方式是通过重写的getObject()来返回的,所以我们直接去看ProxyFactoryBean的getObject()方法:

    ProxyFactoryBean#getObject:

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


这里的逻辑主要有两部分:一个是处理增强链initializeAdvisorChain,还有就是获取代理对象getInstance



initializeAdvisorChain


private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {

    //省略部分代码
     // 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");
     }

     // Materialize interceptor chain from bean names.
     for (String name : this.interceptorNames)
        else {
           // If we get here, we need to add a named interceptor.
           // We must check if it's a singleton or prototype.
           Object advice;
           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, name);
        }
     }
  }

  this.advisorChainInitialized = true;
}


    

private void addAdvisorOnChainCreation(Object next, String name) {
  // We need to convert to an Advisor if necessary so that our source reference
  // matches what we find from superclass interceptors.
  Advisor advisor = namedBeanToAdvisor(next);
  if (logger.isTraceEnabled()) {
     logger.trace("Adding advisor with name '" + name + "'");
  }
  addAdvisor(advisor);
}


/**
* List of Advisors. If an Advice is added, it will be wrapped
* in an Advisor before being added to this List.
*/
private List<Advisor> advisors = new LinkedList<Advisor>();


还记得我们使用ProxyFactoryBean时的参数么:

<bean id="target" class="com.ljw.testSpringMode.aop.advice.Trumpet"></bean>

<bean id="introduction" class="com.ljw.testSpringMode.aop.advice.MonitorIntroduction"/>

<bean id="trumpet" class="org.springframework.aop.framework.ProxyFactoryBean"
   p:proxyInterfaces="com.ljw.testSpringMode.aop.advice.MonitorAccess"
   p:interceptorNames="introduction"
   p:target-ref="target"
   p:proxyTargetClass="true"
/>


我们的interceptorNames参数就是在这个里面使用到,根据这些id,直接获取对应的bean对象,最后使用一个list维护这些增强。


getInstance

    处理完了增强链以后,接着根据bean的类型返回对应的代理示例:

if (isSingleton()) {
  return getSingletonInstance();
}
else {
  if (this.targetName == null) {
     logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
           "Enable prototype proxies by setting the 'targetName' property.");
  }
  return newPrototypeInstance();
}


我们这里关注下单例的场景:

private synchronized Object getSingletonInstance() {
  if (this.singletonInstance == null) {
     this.targetSource = freshTargetSource();
     if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
        // Rely on AOP infrastructure to tell us what interfaces to proxy.
        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);
     this.singletonInstance = getProxy(createAopProxy());
  }
  return this.singletonInstance;
}


这里我们看到了一个熟悉的方法getProxy(),哦,原来ProxyFactoryBean内部获取代理示例的逻辑和FactoryBean是一样的,只不过它利用factoryBean的特性对增强链进行了维护。



总结

    Spring Aop生成代理对象主要有两种方式:jdk和cglib,前者通过反射实现,只能针对接口类,后者通过cglib动态生成子类实现,无法对private 和 final修饰的内容进行代理,Spring AOP的代理级别是方法级别。




欢迎扫码一起交流学习

以上是关于源码学习之AOP-代理对象的生成的主要内容,如果未能解决你的问题,请参考以下文章

spring再学习之AOP准备

源码学习之AOPSpring AOP使用

Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义

框架学习之Spring----AOP and jdbcTemplate

Concurrent包学习之 BlockingQueue源码学习

Spring阶段性学习总结AOP编程入门学习之动态代理实现代码的优化