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();
 }
 
}
 

JdkDynamicAopProxy源码的更多相关文章

  1. SpringAop源码情操陶冶-JdkDynamicAopProxy

    承接前文SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator,本文在前文的基础上稍微简单的分析默认情况下的AOP代理,即JDK静态代理 JdkDyna ...

  2. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  3. Spring源码学习(二)AOP

    ----ProxyFactoryBean这个类,这是AOP使用的入口---- AOP有些特有的概念,如:advisor.advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其 ...

  4. Spring核心框架 - AOP的原理及源码解析

    一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置A ...

  5. AOP执行增强-Spring 源码系列(5)

    AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...

  6. SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator

    本文将对SpringAop中如何为AspectJ切面类创建自动代理的过程作下简单的分析,阅读本文前需要对AOP的Spring相关解析有所了解,具体可见Spring源码情操陶冶-AOP之ConfigBe ...

  7. Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程

    spring-aop-4.3.7.RELEASE  在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...

  8. 异步任务spring @Async注解源码解析

    1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...

  9. Spring提取@Transactional事务注解的源码解析

    声明:本文是自己在学习spring注解事务处理源代码时所留下的笔记: 难免有错误,敬请读者谅解!!! 1.事务注解标签 <tx:annotation-driven /> 2.tx 命名空间 ...

随机推荐

  1. 【英语】Bingo口语笔记(42) - Got系列

  2. 【英语】Bingo口语笔记(50) - Drop系列

  3. Eclipse 打开编辑文件所在文件夹方法

    一个便捷的方法在eclipse的菜单中,依次点击Run->External Tools-> External Tools configurations添加一个新的工具 OpenContai ...

  4. IOS设计模式之四(备忘录模式,命令模式)

    本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq) ...

  5. 微软官方的一段JavaScript判断.net环境

    <HTML> <HEAD> <TITLE>Test for the .NET Framework 3.5</TITLE> <META HTTP-E ...

  6. HDU 4540 威威猫系列故事——打地鼠

    威威猫系列故事--打地鼠 Time Limit: 300/100 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Su ...

  7. C#调用WebService实现天气预报 http://www.webxml.com.cn

     C#调用WebService实现天气预报 2011-02-21 14:24:06 标签:天气预报 休闲 WebServices 职场 C# 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始 ...

  8. [转]Linux之type命令

    转自:http://codingstandards.iteye.com/blog/831504 用途说明 type命令用来显示指定命令的类型.一个命令的类型可以是如下之一 alias 别名 keywo ...

  9. nagios监控远程主机端口

    1 被监控主机上的操作 修改nrpe插件内容: 在其中增加的内容如下: 表示的含义为监控主机的端口631和661,这个主要是监控命令 重启xinetd服务: 2 监控主机上的操作 查看监控命令配置文件 ...

  10. 答 “SOA会不会造成IT黑洞?”

    [文/ 任英杰] 随意间看到支点网的“SOA会不会造成IT黑洞”一文,作者对SOA的认识颇有以偏概全之嫌,写点自己的感想,作为应和吧. 作者的二个对SOA的观点有些偏颇:“SOA就是一种系统集成,它是 ...