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. NodeJS学习笔记之MongoDB模块

    其中还有,nodejs远程连接mysql数据库 一,开篇分析 这篇属于扩展知识篇,因为在下面的文章中会用到数据库操作,所以今天就来说说它(Mongodb模块). (1),简介 MongoDB是一个基于 ...

  2. 自定义View--一个简单地圆形Progress效果

    先看效果图吧 我们要实现一个自定义的再一个圆形中绘制一个弧形的自定义View,思路是这样的: 先要创建一个类ProgressView,继承自View类,然后重写其中的两个构造方法,一个是一个参数的,一 ...

  3. FastJson只序列化java对象的部分属性

    public class Student { private int id; private String name; private int age; //get set方法略 } 如下方法: St ...

  4. OpenGl从零开始之坐标变换(上)

    坐标变换是深入理解三维世界的基础,非常重要.学习这部分首先要清楚几个概念:视点变换.模型变换.投影变换.视口变换. 在现实世界中,所有的物体都具有三维特征,但计算机本身只能处理数字,显示二维的图形,因 ...

  5. python 安装预编译库注意事项-pip

    一般安装依赖库用pip install 库名 就可以,某些情况下依赖的库需要安装预编译好的, 可以参考pip 安装时的错误信息 下面这个链接中可以直接下载 http://www.lfd.uci.edu ...

  6. stringstream实例

    stringstream的具体作用稍后来总结,这里分享一个实例,从txt文档中读取数据,并对进行处理. #include <iostream> #include <sstream&g ...

  7. 【2013微软面试题】输出节点数为n的二叉树的所有形态

    转自:http://blog.csdn.net/monsterxd/article/details/8449005 /* *  题意,求节点数为n的二叉树的所有形态,先要想个方式来唯一标示一棵二叉树 ...

  8. 使用iphone5修剪视频的方法

    iphone5有很高的视频拍摄质量,这人很多业余爱好者也加入了视频短片的拍摄当中.在拍摄视频的过程中,为了能够捕捉到精彩瞬间,常常会提前拍摄,并延迟结束拍摄,这样就给视频增加了很多无意义的片段.这时, ...

  9. 200 OK (from cache) 与 304 Not Modified

    解释: 200 OK (from cache)  是浏览器没有跟服务器确认,直接用了浏览器缓存: 304 Not Modified 是浏览器和服务器多确认了一次缓存有效性,再用的缓存. 触发区别: 2 ...

  10. 为什么数据科学家们选择了Python语言?

    本文由 伯乐在线 - HanSir 翻译,toolate 校稿 英文出处:Quora [伯乐在线导读]:这个问题来自 Quora,题主还补充说,“似乎很多搞数据的程序员都挺擅长 Python 的,这是 ...