源码学习之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的代理级别是方法级别。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值