UDN-企业互联网技术人气社区

板块导航

浏览  : 1060
回复  : 1

[讨论交流] Java JDK 动态代理使用及实现原理分析

[复制链接]
芭芭拉的头像 楼主
  一、什么是代理?

  代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

  代理模式UML图:
1.png

  为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

  二、Java 动态代理类

  Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

  (1)Interface InvocationHandler:该接口中仅定义了一个方法
  1. publicobject invoke(Object obj,Method method, Object[] args)
复制代码

  在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

  (2)Proxy:该类即为动态代理类,其中主要包含以下内容:

  protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

  static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

  static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

  所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

  在使用动态代理类时,我们必须实现InvocationHandler接口

  通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

  动态代理步骤:

  • 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  • 2.创建被代理的类以及接口
  • 3.通过Proxy的静态方法

  1. newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
复制代码

  4.通过代理调用方法

  三、JDK的动态代理怎么使用?

  1、需要动态代理的接口:
  1. package jiankunking;

  2. /**
  3. * 需要动态代理的接口
  4. */
  5. public interface Subject
  6. {
  7.     /**
  8.      * 你好
  9.      *
  10.      * @param name
  11.      * @return
  12.      */
  13.     public String SayHello(String name);

  14.     /**
  15.      * 再见
  16.      *
  17.      * @return
  18.      */
  19.     public String SayGoodBye();
  20. }
复制代码

  2、需要代理的实际对象
  1. package jiankunking;

  2. /**
  3. * 实际对象
  4. */
  5. public class RealSubject implements Subject
  6. {

  7.     /**
  8.      * 你好
  9.      *
  10.      * @param name
  11.      * @return
  12.      */
  13.     public String SayHello(String name)
  14.     {
  15.         return "hello " + name;
  16.     }

  17.     /**
  18.      * 再见
  19.      *
  20.      * @return
  21.      */
  22.     public String SayGoodBye()
  23.     {
  24.         return " good bye ";
  25.     }
  26. }
复制代码

  3、调用处理器实现类
  1. package jiankunking;

  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;


  4. /**
  5. * 调用处理器实现类
  6. * 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象
  7. */
  8. public class InvocationHandlerImpl implements InvocationHandler
  9. {

  10.     /**
  11.      * 这个就是我们要代理的真实对象
  12.      */
  13.     private Object subject;

  14.     /**
  15.      * 构造方法,给我们要代理的真实对象赋初值
  16.      *
  17.      * @param subject
  18.      */
  19.     public InvocationHandlerImpl(Object subject)
  20.     {
  21.         this.subject = subject;
  22.     }

  23.     /**
  24.      * 该方法负责集中处理动态代理类上的所有方法调用。
  25.      * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
  26.      *
  27.      * @param proxy  代理类实例
  28.      * @param method 被调用的方法对象
  29.      * @param args   调用参数
  30.      * @return
  31.      * @throws Throwable
  32.      */
  33.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  34.     {
  35.         //在代理真实对象前我们可以添加一些自己的操作
  36.         System.out.println("在调用之前,我要干点啥呢?");

  37.         System.out.println("Method:" + method);

  38.         //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
  39.         Object returnValue = method.invoke(subject, args);

  40.         //在代理真实对象后我们也可以添加一些自己的操作
  41.         System.out.println("在调用之后,我要干点啥呢?");

  42.         return returnValue;
  43.     }
  44. }
复制代码

  4、测试
  1. package jiankunking;

  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Proxy;

  4. /**
  5. * 动态代理演示
  6. */
  7. public class DynamicProxyDemonstration
  8. {
  9.     public static void main(String[] args)
  10.     {
  11.         //代理的真实对象
  12.         Subject realSubject = new RealSubject();
  13.         
  14.         /**
  15.          * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
  16.          * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
  17.          * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
  18.          */
  19.         InvocationHandler handler = new InvocationHandlerImpl(realSubject);


  20.         ClassLoader loader = handler.getClass().getClassLoader();
  21.         Class[] interfaces = realSubject.getClass().getInterfaces();
  22.         /**
  23.          * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
  24.          */
  25.         Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

  26.         System.out.println("动态代理对象的类型:"+subject.getClass().getName());

  27.         String hello = subject.SayHello("jiankunking");
  28.         System.out.println(hello);
  29. //        String goodbye = subject.SayGoodBye();
  30. //        System.out.println(goodbye);
  31.     }

  32. }
复制代码

  5、输出结果如下:
1.png

 演示demo下载地址:http://download.csdn.net/detail/xunzaosiyecao/9597388

  四、动态代理怎么实现的?

  从使用代码中可以看出,关键点在:
  1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
复制代码

  通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。
也就是说,当代码执行到:

  subject.SayHello(“jiankunking”)这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?

  既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?
  1. public static Object newProxyInstance(ClassLoader loader,
  2.                                           Class>[] interfaces,
  3.                                           InvocationHandler h)
  4.         throws IllegalArgumentException
  5.     {
  6.                 //检查h 不为空,否则抛异常
  7.         Objects.requireNonNull(h);

  8.         final Class>[] intfs = interfaces.clone();
  9.         final SecurityManager sm = System.getSecurityManager();
  10.         if (sm != null) {
  11.             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  12.         }

  13.         /*
  14.          * 获得与指定类装载器和一组接口相关的代理类类型对象
  15.          */
  16.         Class> cl = getProxyClass0(loader, intfs);

  17.         /*
  18.          * 通过反射获取构造函数对象并生成代理类实例
  19.          */
  20.         try {
  21.             if (sm != null) {
  22.                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
  23.             }
  24.                         //获取代理对象的构造方法(也就是$Proxy0(InvocationHandler h))
  25.             final Constructor> cons = cl.getConstructor(constructorParams);
  26.             final InvocationHandler ih = h;
  27.             if (!Modifier.isPublic(cl.getModifiers())) {
  28.                 AccessController.doPrivileged(new PrivilegedAction() {
  29.                     public Void run() {
  30.                         cons.setAccessible(true);
  31.                         return null;
  32.                     }
  33.                 });
  34.             }
  35.                         //生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法
  36.             return cons.newInstance(new Object[]{h});
  37.         } catch (IllegalAccessException|InstantiationException e) {
  38.             throw new InternalError(e.toString(), e);
  39.         } catch (InvocationTargetException e) {
  40.             Throwable t = e.getCause();
  41.             if (t instanceof RuntimeException) {
  42.                 throw (RuntimeException) t;
  43.             } else {
  44.                 throw new InternalError(t.toString(), t);
  45.             }
  46.         } catch (NoSuchMethodException e) {
  47.             throw new InternalError(e.toString(), e);
  48.         }
  49.     }
复制代码

  我们再进去getProxyClass0方法看一下:
  1. /**
  2.      * Generate a proxy class.  Must call the checkProxyAccess method
  3.      * to perform permission checks before calling this.
  4.      */
  5.     private static Class> getProxyClass0(ClassLoader loader,
  6.                                            Class>... interfaces) {
  7.         if (interfaces.length > 65535) {
  8.             throw new IllegalArgumentException("interface limit exceeded");
  9.         }

  10.         // If the proxy class defined by the given loader implementing
  11.         // the given interfaces exists, this will simply return the cached copy;
  12.         // otherwise, it will create the proxy class via the ProxyClassFactory
  13.         return proxyClassCache.get(loader, interfaces);
  14.     }
复制代码

  真相还是没有来到,继续,看一下proxyClassCache
  1. /**
  2.      * a cache of proxy classes
  3.      */
  4.     private static final WeakCache[], Class>>
  5.         proxyClassCache = new WeakCache(new KeyFactory(), new ProxyClassFactory());
复制代码

  奥,原来用了一下缓存啊

  那么它对应的get方法啥样呢?
  1. /**
  2.      * Look-up the value through the cache. This always evaluates the
  3.      * {code subKeyFactory} function and optionally evaluates
  4.      * {code valueFactory} function if there is no entry in the cache for given
  5.      * pair of (key, subKey) or the entry has already been cleared.
  6.      *
  7.      * @param key       possibly null key
  8.      * @param parameter parameter used together with key to create sub-key and
  9.      *                  value (should not be null)
  10.      * @return the cached value (never null)
  11.      * @throws NullPointerException if {code parameter} passed in or
  12.      *                              {code sub-key} calculated by
  13.      *                              {code subKeyFactory} or {code value}
  14.      *                              calculated by {code valueFactory} is null.
  15.      */
  16.     public V get(K key, P parameter) {
  17.         Objects.requireNonNull(parameter);

  18.         expungeStaleEntries();

  19.         Object cacheKey = CacheKey.valueOf(key, refQueue);

  20.         // lazily install the 2nd level valuesMap for the particular cacheKey
  21.         ConcurrentMap> valuesMap = map.get(cacheKey);
  22.         if (valuesMap == null) {
  23.                         //putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入
  24.             ConcurrentMap> oldValuesMap
  25.                 = map.putIfAbsent(cacheKey,
  26.                                   valuesMap = new ConcurrentHashMap());
  27.             if (oldValuesMap != null) {
  28.                 valuesMap = oldValuesMap;
  29.             }
  30.         }

  31.         // create subKey and retrieve the possible Supplier stored by that
  32.         // subKey from valuesMap
  33.         Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  34.         Supplier supplier = valuesMap.get(subKey);
  35.         Factory factory = null;

  36.         while (true) {
  37.             if (supplier != null) {
  38.                 // supplier might be a Factory or a CacheValue instance
  39.                 V value = supplier.get();
  40.                 if (value != null) {
  41.                     return value;
  42.                 }
  43.             }
  44.             // else no supplier in cache
  45.             // or a supplier that returned null (could be a cleared CacheValue
  46.             // or a Factory that wasn't successful in installing the CacheValue)

  47.             // lazily construct a Factory
  48.             if (factory == null) {
  49.                 factory = new Factory(key, parameter, subKey, valuesMap);
  50.             }

  51.             if (supplier == null) {                                
  52.                 supplier = valuesMap.putIfAbsent(subKey, factory);
  53.                 if (supplier == null) {
  54.                     // successfully installed Factory
  55.                     supplier = factory;
  56.                 }
  57.                 // else retry with winning supplier
  58.             } else {
  59.                 if (valuesMap.replace(subKey, supplier, factory)) {
  60.                     // successfully replaced
  61.                     // cleared CacheEntry / unsuccessful Factory
  62.                     // with our Factory
  63.                     supplier = factory;
  64.                 } else {
  65.                     // retry with current supplier
  66.                     supplier = valuesMap.get(subKey);
  67.                 }
  68.             }
  69.         }
  70.     }
复制代码

  我们可以看到它调用了 supplier.get(); 获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。
来瞅瞅,get里面又做了什么?
  1. public synchronized V get() { // serialize access
  2.             // re-check
  3.             Supplier supplier = valuesMap.get(subKey);
  4.             if (supplier != this) {
  5.                 // something changed while we were waiting:
  6.                 // might be that we were replaced by a CacheValue
  7.                 // or were removed because of failure ->
  8.                 // return null to signal WeakCache.get() to retry
  9.                 // the loop
  10.                 return null;
  11.             }
  12.             // else still us (supplier == this)

  13.             // create new value
  14.             V value = null;
  15.             try {
  16.                 value = Objects.requireNonNull(valueFactory.apply(key, parameter));
  17.             } finally {
  18.                 if (value == null) { // remove us on failure
  19.                     valuesMap.remove(subKey, this);
  20.                 }
  21.             }
  22.             // the only path to reach here is with non-null value
  23.             assert value != null;

  24.             // wrap value with CacheValue (WeakReference)
  25.             CacheValue cacheValue = new CacheValue(value);

  26.             // try replacing us with CacheValue (this should always succeed)
  27.             if (valuesMap.replace(subKey, this, cacheValue)) {
  28.                 // put also in reverseMap
  29.                 reverseMap.put(cacheValue, Boolean.TRUE);
  30.             } else {
  31.                 throw new AssertionError("Should not reach here");
  32.             }

  33.             // successfully replaced us with new CacheValue -> return the value
  34.             // wrapped by it
  35.             return value;
  36.         }
  37.     }
复制代码

  发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key, parameter)方法:
  1. /**
  2.      * A factory function that generates, defines and returns the proxy class given
  3.      * the ClassLoader and array of interfaces.
  4.      */
  5.     private static final class ProxyClassFactory
  6.         implements BiFunction[], Class>>
  7.     {
  8.         // prefix for all proxy class names
  9.         private static final String proxyClassNamePrefix = "$Proxy";

  10.         // next number to use for generation of unique proxy class names
  11.         private static final AtomicLong nextUniqueNumber = new AtomicLong();

  12.         @Override
  13.         public Class> apply(ClassLoader loader, Class>[] interfaces) {

  14.             Map, Boolean> interfaceSet = new IdentityHashMap(interfaces.length);
  15.             for (Class> intf : interfaces) {
  16.                 /*
  17.                  * Verify that the class loader resolves the name of this
  18.                  * interface to the same Class object.
  19.                  */
  20.                 Class> interfaceClass = null;
  21.                 try {
  22.                     interfaceClass = Class.forName(intf.getName(), false, loader);
  23.                 } catch (ClassNotFoundException e) {
  24.                 }
  25.                 if (interfaceClass != intf) {
  26.                     throw new IllegalArgumentException(
  27.                         intf + " is not visible from class loader");
  28.                 }
  29.                 /*
  30.                  * Verify that the Class object actually represents an
  31.                  * interface.
  32.                  */
  33.                 if (!interfaceClass.isInterface()) {
  34.                     throw new IllegalArgumentException(
  35.                         interfaceClass.getName() + " is not an interface");
  36.                 }
  37.                 /*
  38.                  * Verify that this interface is not a duplicate.
  39.                  */
  40.                 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
  41.                     throw new IllegalArgumentException(
  42.                         "repeated interface: " + interfaceClass.getName());
  43.                 }
  44.             }

  45.             String proxyPkg = null;     // package to define proxy class in
  46.             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

  47.             /*
  48.              * Record the package of a non-public proxy interface so that the
  49.              * proxy class will be defined in the same package.  Verify that
  50.              * all non-public proxy interfaces are in the same package.
  51.              */
  52.             for (Class> intf : interfaces) {
  53.                 int flags = intf.getModifiers();
  54.                 if (!Modifier.isPublic(flags)) {
  55.                     accessFlags = Modifier.FINAL;
  56.                     String name = intf.getName();
  57.                     int n = name.lastIndexOf('.');
  58.                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  59.                     if (proxyPkg == null) {
  60.                         proxyPkg = pkg;
  61.                     } else if (!pkg.equals(proxyPkg)) {
  62.                         throw new IllegalArgumentException(
  63.                             "non-public interfaces from different packages");
  64.                     }
  65.                 }
  66.             }

  67.             if (proxyPkg == null) {
  68.                 // if no non-public proxy interfaces, use com.sun.proxy package
  69.                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  70.             }

  71.             /*
  72.              * Choose a name for the proxy class to generate.
  73.              */
  74.             long num = nextUniqueNumber.getAndIncrement();
  75.             String proxyName = proxyPkg + proxyClassNamePrefix + num;

  76.             /*
  77.              * Generate the specified proxy class.
  78.              */
  79.             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  80.                 proxyName, interfaces, accessFlags);
  81.             try {
  82.                 return defineClass0(loader, proxyName,
  83.                                     proxyClassFile, 0, proxyClassFile.length);
  84.             } catch (ClassFormatError e) {
  85.                 /*
  86.                  * A ClassFormatError here means that (barring bugs in the
  87.                  * proxy class generation code) there was some other
  88.                  * invalid aspect of the arguments supplied to the proxy
  89.                  * class creation (such as virtual machine limitations
  90.                  * exceeded).
  91.                  */
  92.                 throw new IllegalArgumentException(e.toString());
  93.             }
  94.         }
  95.     }
复制代码

  通过看代码终于找到了重点:
  1. //生成字节码
  2. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
复制代码

  那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:
  1. package jiankunking;

  2. import sun.misc.ProxyGenerator;

  3. import java.io.File;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.lang.reflect.InvocationHandler;
  8. import java.lang.reflect.Proxy;

  9. /**
  10. * 动态代理演示
  11. */
  12. public class DynamicProxyDemonstration
  13. {
  14.     public static void main(String[] args)
  15.     {
  16.         //代理的真实对象
  17.         Subject realSubject = new RealSubject();

  18.         /**
  19.          * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
  20.          * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
  21.          * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
  22.          */
  23.         InvocationHandler handler = new InvocationHandlerImpl(realSubject);

  24.         ClassLoader loader = handler.getClass().getClassLoader();
  25.         Class[] interfaces = realSubject.getClass().getInterfaces();
  26.         /**
  27.          * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
  28.          */
  29.         Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

  30.         System.out.println("动态代理对象的类型:"+subject.getClass().getName());

  31.         String hello = subject.SayHello("jiankunking");
  32.         System.out.println(hello);
  33.         // 将生成的字节码保存到本地,
  34.         createProxyClassFile();
  35.     }
  36.     private static void createProxyClassFile(){
  37.         String name = "ProxySubject";
  38.         byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});
  39.         FileOutputStream out =null;
  40.         try {
  41.             out = new FileOutputStream(name+".class");
  42.             System.out.println((new File("hello")).getAbsolutePath());
  43.             out.write(data);
  44.         } catch (FileNotFoundException e) {
  45.             e.printStackTrace();
  46.         } catch (IOException e) {
  47.             e.printStackTrace();
  48.         }finally {
  49.             if(null!=out) try {
  50.                 out.close();
  51.             } catch (IOException e) {
  52.                 e.printStackTrace();
  53.             }
  54.         }
  55.     }

  56. }
复制代码

  我们用jd-jui 工具将生成的字节码反编译:
  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. import java.lang.reflect.UndeclaredThrowableException;
  5. import jiankunking.Subject;

  6. public final class ProxySubject
  7.   extends Proxy
  8.   implements Subject
  9. {
  10.   private static Method m1;
  11.   private static Method m3;
  12.   private static Method m4;
  13.   private static Method m2;
  14.   private static Method m0;
  15.   
  16.   public ProxySubject(InvocationHandler paramInvocationHandler)
  17.   {
  18.     super(paramInvocationHandler);
  19.   }
  20.   
  21.   public final boolean equals(Object paramObject)
  22.   {
  23.     try
  24.     {
  25.       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  26.     }
  27.     catch (Error|RuntimeException localError)
  28.     {
  29.       throw localError;
  30.     }
  31.     catch (Throwable localThrowable)
  32.     {
  33.       throw new UndeclaredThrowableException(localThrowable);
  34.     }
  35.   }
  36.   
  37.   public final String SayGoodBye()
  38.   {
  39.     try
  40.     {
  41.       return (String)this.h.invoke(this, m3, null);
  42.     }
  43.     catch (Error|RuntimeException localError)
  44.     {
  45.       throw localError;
  46.     }
  47.     catch (Throwable localThrowable)
  48.     {
  49.       throw new UndeclaredThrowableException(localThrowable);
  50.     }
  51.   }
  52.   
  53.   public final String SayHello(String paramString)
  54.   {
  55.     try
  56.     {
  57.       return (String)this.h.invoke(this, m4, new Object[] { paramString });
  58.     }
  59.     catch (Error|RuntimeException localError)
  60.     {
  61.       throw localError;
  62.     }
  63.     catch (Throwable localThrowable)
  64.     {
  65.       throw new UndeclaredThrowableException(localThrowable);
  66.     }
  67.   }
  68.   
  69.   public final String toString()
  70.   {
  71.     try
  72.     {
  73.       return (String)this.h.invoke(this, m2, null);
  74.     }
  75.     catch (Error|RuntimeException localError)
  76.     {
  77.       throw localError;
  78.     }
  79.     catch (Throwable localThrowable)
  80.     {
  81.       throw new UndeclaredThrowableException(localThrowable);
  82.     }
  83.   }
  84.   
  85.   public final int hashCode()
  86.   {
  87.     try
  88.     {
  89.       return ((Integer)this.h.invoke(this, m0, null)).intValue();
  90.     }
  91.     catch (Error|RuntimeException localError)
  92.     {
  93.       throw localError;
  94.     }
  95.     catch (Throwable localThrowable)
  96.     {
  97.       throw new UndeclaredThrowableException(localThrowable);
  98.     }
  99.   }
  100.   
  101.   static
  102.   {
  103.     try
  104.     {
  105.       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
  106.       m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);
  107.       m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") });
  108.       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  109.       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  110.       return;
  111.     }
  112.     catch (NoSuchMethodException localNoSuchMethodException)
  113.     {
  114.       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  115.     }
  116.     catch (ClassNotFoundException localClassNotFoundException)
  117.     {
  118.       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  119.     }
  120.   }
  121. }
复制代码

  这就是最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口

  也就是说:
  1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
复制代码

  这里的subject实际是这个类的一个实例,那么我们调用它的:
  1. public final String SayHello(String paramString)
复制代码

  就是调用我们定义的InvocationHandlerImpl的 invoke方法:
1.png

  五、结论

  到了这里,终于解答了:

  subject.SayHello(“jiankunking”)这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?

  因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,在实现Subject接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。

  包含生成本地class文件的demo:http://download.csdn.net/detail/xunzaosiyecao/9597474

  通过分析代码可以看出Java 动态代理,具体有如下四步骤:

  • 通过实现 InvocationHandler 接口创建自己的调用处理器;
  • 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  • 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

相关帖子

发表于 2016-9-18 14:52:12 | 显示全部楼层
深深受益
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部