zoukankan      html  css  js  c++  java
  • JdkDynamicAopProxy源码

     JdkDynamicAopProxy是通过接口实现动态代理类,主要方法是getProxy(ClassLoader classLoader), 代理类生成之后再调用目标方法时就会调用invoke方法。

    package org.springframework.aop.framework;
     
    import java.io.Serializable;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.List;
     
    import org.aopalliance.intercept.MethodInvocation;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
     
    import org.springframework.aop.AopInvocationException;
    import org.springframework.aop.RawTargetAccess;
    import org.springframework.aop.TargetSource;
    import org.springframework.aop.support.AopUtils;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
     
    /**
     * JDK-based {@link AopProxy} implementation for the Spring AOP framework,
     * based on JDK {@link java.lang.reflect.Proxy dynamic proxies}.
     *
     * <p>Creates a dynamic proxy, implementing the interfaces exposed by
     * the AopProxy. Dynamic proxies <i>cannot</i> be used to proxy methods
     * defined in classes, rather than interfaces.
     *
     * <p>Objects of this type should be obtained through proxy factories,
     * configured by an {@link AdvisedSupport} class. This class is internal
     * to Spring's AOP framework and need not be used directly by client code.
     *
     * <p>Proxies created using this class will be thread-safe if the
     * underlying (target) class is thread-safe.
     *
     * <p>Proxies are serializable so long as all Advisors (including Advices
     * and Pointcuts) and the TargetSource are serializable.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @author Rob Harrop
     * @author Dave Syer
     * @see java.lang.reflect.Proxy
     * @see AdvisedSupport
     * @see ProxyFactory
     */
    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
     
     /** use serialVersionUID from Spring 1.2 for interoperability */
     private static final long serialVersionUID = 5531744639992436476L;
     
     
     /*
      * NOTE: We could avoid the code duplication between this class and the CGLIB
      * proxies by refactoring "invoke" into a template method. However, this approach
      * adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice
      * elegance for performance. (We have a good test suite to ensure that the different
      * proxies behave the same :-)
      * This way, we can also more easily take advantage of minor optimizations in each class.
      */
     
     /** We use a static Log to avoid serialization issues */
     private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
     
     /** Config used to configure this proxy */
     private final AdvisedSupport advised;
     
     /**
      * Is the {@link #equals} method defined on the proxied interfaces?
      */
     private boolean equalsDefined;
     
     /**
      * Is the {@link #hashCode} method defined on the proxied interfaces?
      */
     private boolean hashCodeDefined;
     
     
     /**
      * Construct a new JdkDynamicAopProxy for the given AOP configuration.
      * @param config the AOP configuration as AdvisedSupport object
      * @throws AopConfigException if the config is invalid. We try to throw an informative
      * exception in this case, rather than let a mysterious failure happen later.
      */
     public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
      Assert.notNull(config, "AdvisedSupport must not be null");
      if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
       throw new AopConfigException("No advisors and no TargetSource specified");
      }
      this.advised = config;
     }
     
     
     @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);
     }
     
     /**
      * Finds any {@link #equals} or {@link #hashCode} method that may be defined
      * on the supplied set of interfaces.
      * @param proxiedInterfaces the interfaces to introspect
      */
     private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
      for (Class<?> proxiedInterface : proxiedInterfaces) {
       Method[] methods = proxiedInterface.getDeclaredMethods();
       for (Method method : methods) {
        if (AopUtils.isEqualsMethod(method)) {
         this.equalsDefined = true;
        }
        if (AopUtils.isHashCodeMethod(method)) {
         this.hashCodeDefined = true;
        }
        if (this.equalsDefined && this.hashCodeDefined) {
         return;
        }
       }
      }
     }
     
     
     /**
      * Implementation of {@code InvocationHandler.invoke}.
      * <p>Callers will see exactly the exception thrown by the target,
      * unless a hook method throws an exception.
      */
     @Override
     public Object  invoke(Object proxy, Method method, Object[] args) throws Throwable {
      MethodInvocation invocation;
      Object oldProxy = null;
      boolean setProxyContext = false;
     
      TargetSource targetSource = this.advised.targetSource;
      Class<?> targetClass = null;
      Object target = null;
     
      try {
       if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
        // The target does not implement the equals(Object) method itself.
        return equals(args[0]);
       }
       if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
        // The target does not implement the hashCode() method itself.
        return hashCode();
       }
       if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
         method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        // Service invocations on ProxyConfig with the proxy config...
        return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
       }
     
       Object retVal;
     
       if (this.advised.exposeProxy) {
        // Make invocation available if necessary.
        oldProxy = AopContext.setCurrentProxy(proxy);
        setProxyContext = true;
       }
     
       // May be null. Get as late as possible to minimize the time we "own" the target,
       // in case it comes from a pool.
       target = targetSource.getTarget();
       if (target != null) {
        targetClass = target.getClass();
       }
     
       // Get the interception chain for this method.
       List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
     
       // Check whether we have any advice. If we don't, we can fallback on direct
       // reflective invocation of the target, and avoid creating a MethodInvocation.
       if (chain.isEmpty()) {
        // We can skip creating a MethodInvocation: just invoke the target directly
        // Note that the final invoker must be an InvokerInterceptor so we know it does
        // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
       }
       else {
        // We need to create a method invocation...
        invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        // Proceed to the joinpoint through the interceptor chain.
        retVal = invocation.proceed();
       }
     
       // Massage return value if necessary.
       Class<?> returnType = method.getReturnType();
       if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
         !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
        // Special case: it returned "this" and the return type of the method
        // is type-compatible. Note that we can't help if the target sets
        // a reference to itself in another returned object.
        retVal = proxy;
       }
       else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
        throw new AopInvocationException(
          "Null return value from advice does not match primitive return type for: " + method);
       }
       return retVal;
      }
      finally {
       if (target != null && !targetSource.isStatic()) {
        // Must have come from TargetSource.
        targetSource.releaseTarget(target);
       }
       if (setProxyContext) {
        // Restore old proxy.
        AopContext.setCurrentProxy(oldProxy);
       }
      }
     }
     
     
     /**
      * Equality means interfaces, advisors and TargetSource are equal.
      * <p>The compared object may be a JdkDynamicAopProxy instance itself
      * or a dynamic proxy wrapping a JdkDynamicAopProxy instance.
      */
     @Override
     public boolean equals(Object other) {
      if (other == this) {
       return true;
      }
      if (other == null) {
       return false;
      }
     
      JdkDynamicAopProxy otherProxy;
      if (other instanceof JdkDynamicAopProxy) {
       otherProxy = (JdkDynamicAopProxy) other;
      }
      else if (Proxy.isProxyClass(other.getClass())) {
       InvocationHandler ih = Proxy.getInvocationHandler(other);
       if (!(ih instanceof JdkDynamicAopProxy)) {
        return false;
       }
       otherProxy = (JdkDynamicAopProxy) ih;
      }
      else {
       // Not a valid comparison...
       return false;
      }
     
      // If we get here, otherProxy is the other AopProxy.
      return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);
     }
     
     /**
      * Proxy uses the hash code of the TargetSource.
      */
     @Override
     public int hashCode() {
      return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
     }
     
    }
     
  • 相关阅读:
    python初体验-函数(1)
    python初体验-数值类型
    python初体验-常见错误类型
    动态规划专题——passage_1
    七夕——ORMAX(线段树)
    七夕——永远在一起(一维dp)
    动态规划4.4——背包问题
    动态规划4.3——最长公共子串问题
    动态规划4.2——子序列问题
    动态规划4.1——基础动态规划问题
  • 原文地址:https://www.cnblogs.com/lsx1993/p/4631530.html
Copyright © 2011-2022 走看看