`
m635674608
  • 浏览: 5028757 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

JDK动态代理源码Proxy

 
阅读更多
public static Object newProxyInstance(ClassLoader loader,
       Class<?>[] interfaces,
       InvocationHandler h)//这里有三个参数,第一个是传入classloader,一般情况是传入当前的classloader.但是我在上一节模拟实现里传入的是URL loader..第二个参数表示的是接口,第三个是Invocationhandler,除了第一个参数,其他和我在上一节里的一样.JDK的封装的比较好,所以他传入的是Interface的数组,
 throws IllegalArgumentException
    {
 if (h == null) {
     throw new NullPointerException();//如果Invocationhandler 为空,抛异常
 }

 /*
  * Look up or generate the designated proxy class.这个方法里最主要的地方在这里,它直接通过调用 getProxyClass方法获取到了自动生成的动态代理类的二进制码.在我上一节的内容里,我们是通过自己生成JAVA文件,然后通过JAVA文件动态编译成对应的class文件,然后通过URLClassLoader.loadClass("com.cjb.proxy.Proxy1");这个方法来获取对应的二进制码的.这个方法下面会继续解释.
  */
 Class cl = getProxyClass(loader, interfaces);

 /*
  * Invoke its constructor with the designated invocation handler.这个方法就是获取对应class的Constructor,然后通过这个Constructor来实例化..
  */
 try {
     Constructor cons = cl.getConstructor(constructorParams);
     return (Object) cons.newInstance(new Object[] { h });
 } catch (NoSuchMethodException e) {
     throw new InternalError(e.toString());
 } catch (IllegalAccessException e) {
     throw new InternalError(e.toString());
 } catch (InstantiationException e) {
     throw new InternalError(e.toString());
 } catch (InvocationTargetException e) {
     throw new InternalError(e.toString());
 }
    }

上面的方法,除了最重要的getProxyClass,其他都很容易理解.,那么下面开始读getProxyClass方法

public static Class<?> getProxyClass(ClassLoader loader, 
                                         Class<?>... interfaces)
 throws IllegalArgumentException
    {
 if (interfaces.length > 65535) {
     throw new IllegalArgumentException("interface limit exceeded");//JDK想的果然比较到位,连interface传的太多都想到了..~!~
 }

 Class proxyClass = null;//这个就是最后要生成的二进制码,首先初始化一下

 /* collect interface names to use as key for proxy class cache */
 String[] interfaceNames = new String[interfaces.length];//这个存放的是对应的Interface的名字..

 Set interfaceSet = new HashSet(); //这个HashSet 是为了检测interface重复记录的.

 for (int i = 0; i < interfaces.length; i++) {
     /*
      * Verify that the class loader resolves the name of this
      * interface to the same Class object.
      */
     String interfaceName = interfaces[i].getName();
     Class interfaceClass = null;
     try {
  interfaceClass = Class.forName(interfaceName, false, loader);//创建对应接口的二进制码,第二个参数false表示,不需要初始化
     } catch (ClassNotFoundException e) {
     }
     if (interfaceClass != interfaces[i]) {//如果创建出来的二进制码和原来的接口不一样,表示这个接口对于这个classloader来说是不可见的
  throw new IllegalArgumentException(
      interfaces[i] + " is not visible from class loader");
     }

     /*
      * Verify that the Class object actually represents an
      * interface.
      */
     if (!interfaceClass.isInterface()) {//如果不是接口,那么就抛异常,这里就规定了,我们必须通过接口来代理..或者说,必须面向接口编程
  throw new IllegalArgumentException(
      interfaceClass.getName() + " is not an interface");
     }

     /*
      * Verify that this interface is not a duplicate.前面说,InterfaceSet是拿来判断对应的interface接口是否有重复的.这里的方法是:在循环interfaces的时候,把每个interface都添加到interfaceSet里..当然,在添加之前会判断,当前循环到的接口在InterfaceSet里是否有,如果已经有了,则抛异常,说这个接口重复了..没有,则添加..
      */
     if (interfaceSet.contains(interfaceClass)) {
  throw new IllegalArgumentException(
      "repeated interface: " + interfaceClass.getName());
     }
     interfaceSet.add(interfaceClass);

     interfaceNames[i] = interfaceName;//这句就是把每个接口名放到interfaceNames数组里..
 }

 /*
  * Using string representations of the proxy interfaces as
  * keys in the proxy class cache (instead of their Class
  * objects) is sufficient because we require the proxy
  * interfaces to be resolvable by name through the supplied
  * class loader, and it has the advantage that using a string
  * representation of a class makes for an implicit weak
  * reference to the class.
  */
 Object key = Arrays.asList(interfaceNames);//这里把Interface数组转换成list..这里直接写成了Object类型

 /*
  * Find or create the proxy class cache for the class loader.
  */
 Map cache;//放缓存的Map
 synchronized (loaderToCache) {//loaderToCache也是一个Map.它的key是classloader,对应的value是对应的缓存,也是一个HashMap.他把对应的不同的classloader放到loaderToCache里,如果下次还要调用这个方法创建代理,并传入的是同一个classloader,那么可以直接从cache里取..增加速度.当然,如果没有,则创建一条记录,放到loaderToCache里
     cache = (Map) loaderToCache.get(loader);
     if (cache == null) {
  cache = new HashMap();
  loaderToCache.put(loader, cache);
     }
     /*
      * This mapping will remain valid for the duration of this
      * method, without further synchronization, because the mapping
      * will only be removed if the class loader becomes unreachable.
      */
 }

 /*
  * Look up the list of interfaces in the proxy class cache using
  * the key.  This lookup will result in one of three possible
  * kinds of values:
  *     null, if there is currently no proxy class for the list of
  *         interfaces in the class loader,
  *     the pendingGenerationMarker object, if a proxy class for the
  *         list of interfaces is currently being generated,
  *     or a weak reference to a Class object, if a proxy class for
  *         the list of interfaces has already been generated.
  */
 synchronized (cache) {
     /*
      * Note that we need not worry about reaping the cache for
      * entries with cleared weak references because if a proxy class
      * has been garbage collected, its class loader will have been
      * garbage collected as well, so the entire cache will be reaped
      * from the loaderToCache map.
      */
     do {
  Object value = cache.get(key);//这里从cache里获取对应的Object..第一次执行的话,明显获取到的是Null..key表示的是用接口名字转换而来的list..这个可以看上面的代码.
  if (value instanceof Reference) {
      proxyClass = (Class) ((Reference) value).get();//如果已经能获取到了,那么,我们需要的二进制码文件就是这个获取到的
  }
  if (proxyClass != null) {
      // proxy class already generated: return it
      return proxyClass;
  } else if (value == pendingGenerationMarker) {//这里的pendingGenerationMarker是一个静态常量,表示 new Object().JDK给出的 解释是,如果代理正在创建,那么等待他
      // proxy class being generated: wait for it
      try {
   cache.wait();
      } catch (InterruptedException e) {
   /*
    * The class generation that we are waiting for should
    * take a small, bounded time, so we can safely ignore
    * thread interrupts here.
    */
      }
      continue;
  } else {
      /*
       * No proxy class for this list of interfaces has been
       * generated or is being generated, so we will go and
       * generate it now.  Mark it as pending generation.
       */
      cache.put(key, pendingGenerationMarker);//如果cache里获取到的对应于key的value是Null ,那么,就创建一个object对象放进去.上面说了,pendingGenerationMarker= new Object();
      break;
  }
     } while (true);
 }

 try {
     String proxyPkg = null; // package to define proxy class in 这个是代理类的包名

     /*
      * Record the package of a non-public proxy interface so that the
      * proxy class will be defined in the same package.  Verify that
      * all non-public proxy interfaces are in the same package.
      */
     for (int i = 0; i < interfaces.length; i++) {
  int flags = interfaces[i].getModifiers();//getModifiers()方法返回的是该接口的修饰类型,用Int类型表示
  if (!Modifier.isPublic(flags)) {//如果不是public 的接口..

  //我们可以这样理解,我们动态创建的代理,他的修饰类型必须是和接口的修饰类型是一样的,我们知道,接口可以是public或者默认,两种修饰类型.这里的判断如果不是public接口,那么,该接口肯定是默认的,如果是默认修饰类型,那么,它只能被同一个包下面的类看到,所以,就必须为该代理类创建一个包名..当然,如果是public的话,就没必要,因为,反正所有的类都能看到..
      String name = interfaces[i].getName();
      int n = name.lastIndexOf('.');
      String pkg = ((n == -1) ? "" : name.substring(0, n + 1));//注意这里的N+1 ,其实是包括 "."的..比如 com.cjb.proxy.Proxy..它返回的就是"com.cjb.proxy."注意最后的那个点

      if (proxyPkg == null) {
   proxyPkg = pkg;
      } else if (!pkg.equals(proxyPkg)) {
   throw new IllegalArgumentException(
       "non-public interfaces from different packages");
      }
  }
     }

     if (proxyPkg == null) { // if no non-public proxy interfaces,这里可以看到,如果是public 的接口,对应代理类的包名就是"",也就是没有包名
  proxyPkg = "";  // use the unnamed package
     }

     {
  /*
   * Choose a name for the proxy class to generate.
   */
  long num;
  synchronized (nextUniqueNumberLock) {
      num = nextUniqueNumber++;//Num是一个计数器.用处是,创建代理的类名的时候用..我们可以看到,它是初始值是0.然后,每被调用一次,Num++.
  }
  String proxyName = proxyPkg + proxyClassNamePrefix + num;//proxyPkg是之前生成的包名, proxyClassNamePrefix 是一个静态常量,proxyClassNamePrefix="$Proxy".最后Num是计数器.也就是说,它的代理类的名字是从 $Proxy1 $Proxy2 $Proxy3一直在增长的,这样的话,就避免了重复.
  /*
   * Verify that the class loader hasn't already
   * defined a class with the chosen name.
   */

  /*
   * Generate the specified proxy class.下面打红字的两个方法是最后生成代理对象的..但是,很悲剧的是,他是用native修饰的,也就是说,它是不是用java来实现的..也就是说,最最关键的地方,不是用java实现的...
   */
  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
      proxyName, interfaces);
  try {
      proxyClass = defineClass0(loader, proxyName,
   proxyClassFile, 0, proxyClassFile.length);
  } catch (ClassFormatError e) {
      /*
       * A ClassFormatError here means that (barring bugs in the
       * proxy class generation code) there was some other
       * invalid aspect of the arguments supplied to the proxy
       * class creation (such as virtual machine limitations
       * exceeded).
       */
      throw new IllegalArgumentException(e.toString());
  }
     }
     // add to set of all generated proxy classes, for isProxyClass
     proxyClasses.put(proxyClass, null);

 } finally {
     /*
      * We must clean up the "pending generation" state of the proxy
      * class cache entry somehow.  If a proxy class was successfully
      * generated, store it in the cache (with a weak reference);
      * otherwise, remove the reserved entry.  In all cases, notify
      * all waiters on reserved entries in this cache.
      */
     synchronized (cache) {
  if (proxyClass != null) {
      cache.put(key, new WeakReference(proxyClass));
  } else {
      cache.remove(key);
  }
  cache.notifyAll();
     }
 }
 return proxyClass;
    }

 

分享到:
评论

相关推荐

    关于jdk动态代理的源码剖析

    ### 关于JDK动态代理的源码剖析 #### 一、引言 在Java开发过程中,动态代理技术是一项非常实用的技术,它可以帮助我们实现在不修改原有代码的基础上为方法增加额外的功能,比如日志记录、权限校验等。本文将深入...

    JDK动态代理源码

    1. **Java.lang.reflect.Proxy**:这是JDK动态代理的关键类,它提供了创建动态代理对象的工厂方法`newProxyInstance()`。这个方法接收三个参数:`ClassLoader`用于加载代理类,`Interface[]`表示代理对象需要实现的...

    浅谈JDK动态代理与CGLIB代理去区别

    首先,JDK动态代理主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。Proxy类用于创建一个代理对象,而InvocationHandler接口则定义了处理代理对象调用方法的逻辑。当调用代理对象的...

    代理模式,JDK动态代理,SpringAOP来龙去脉

    JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。Proxy类是生成代理对象的工厂,而InvocationHandler接口定义了调用处理程序的接口,用于处理对代理对象的方法调用...

    jdk动态代理和CGlib动态代理

    1. **Proxy类**:这是JDK动态代理的核心类,它提供了`newProxyInstance()`静态方法,用于创建代理对象。 2. **InvocationHandler接口**:每个代理对象都关联一个`InvocationHandler`实例。当代理对象的方法被调用时...

    JDK动态代理和Cglib动态代理实例源码

    本篇将详细探讨JDK动态代理和Cglib动态代理,并通过源码实例来加深理解。 首先,JDK动态代理是Java内置的一种机制,它依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。`Proxy`类...

    JDK动态代理在EJB3(包括WebService)中的应用

    标题 "JDK动态代理在EJB3(包括WebService)中的应用" 暗示了本文将探讨Java开发中的一种重要技术——JDK动态代理,以及它如何在企业级JavaBean (EJB) 3.x版本及其相关的Web服务实现中发挥作用。EJB3是Java EE平台的...

    JDK8完整源码包

    源码分析可以揭示其如何实现高效调用,以及如何与Java代理(Proxy)、动态语言支持等特性相互配合。 总之,"JDK8完整源码包"是一个宝贵的学习资源,它涵盖了Java开发的核心技术和优化策略。通过深入研究,开发者不仅...

    CGLIB 和 JDK生成动态代理类的区别

    首先,JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。JDK动态代理只能为实现了至少一个接口的类生成代理。它的基本原理是利用反射机制生成一个实现了目标接口的...

    jdk动态代理 + 拦截器实现小例

    在这个“jdk动态代理 + 拦截器实现小例”中,我们将探讨如何利用Java的InvocationHandler接口和Proxy类来实现拦截器模式,以实现灵活的代码扩展和日志记录、性能监控等需求。 首先,让我们理解什么是动态代理。在...

    java设计模式【之】JDK动态代理【源码】【场景:帮爸爸买菜】.rar

    java设计模式【之】JDK动态代理【源码】【场景:帮爸爸买菜】.rar /** * 代理模式 * 在开发者的角度来看,创建一个代理对象,提供给用户使用,避免用户直接访问真正的对象 * 在用户角度来看,就是普通的类方法...

    jdk动态代理 cglib3.0动态代理

    JDK动态代理基于Java反射API实现,它提供了`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。`Proxy`类用于创建动态代理实例,而`InvocationHandler`接口则定义了处理方法调用的逻辑。 1....

    JDK的动态代理总结

    首先,我们要了解JDK动态代理的核心类——`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`。`Proxy`类用于生成动态代理类,而`InvocationHandler`接口则定义了代理对象处理方法调用的逻辑。 1. ...

    JDK和CGlib分别实现的动态代理源代码

    JDK和CGlib是两种常用的动态代理实现方式,它们各自有不同的特性和使用场景。 首先,我们来详细了解一下JDK动态代理。JDK动态代理基于接口实现,它要求被代理的对象必须实现至少一个接口。通过`java.lang.reflect....

    JDK动态代理demo

    JDK动态代理主要通过`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`两个类来实现。`Proxy`类是用于生成动态代理类和实例的工具,而`InvocationHandler`接口定义了代理对象处理方法调用的逻辑。 ...

    从JDK动态代理到spring AOP

    本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...

    JDK的动态代理(powernode 文档)(源代码)

    JDK的动态代理(powernode 文档)(源代码) JDK的动态代理(powernode 文档) 一、动态代理 1.1JDK动态代理 1.1.1 proxy 1.1.2 InvocationHandler 1.1.3 创建一个Maven项目 1.1.4 导入Spring的相关依赖 1.1.5 修改...

    jdk动态代理使用[文].pdf

    在Java编程中,JDK动态代理是一种强大的工具,它允许我们在运行时创建代理类来拦截对目标对象的调用,从而实现额外的功能,比如日志记录、性能监控、事务管理等,而无需修改原始代码。这里我们将深入探讨JDK动态代理...

    从JDK动态代理看Spring之AOP实现

    本文将深入探讨Spring是如何通过JDK的动态代理来实现AOP的。 首先,我们要理解JDK动态代理的基本原理。在Java中,动态代理主要由`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口组成。...

Global site tag (gtag.js) - Google Analytics