http://blog.csdn.net/jiankunking

【原创】自己动手实现JDK动态代理 (可以自己完全手写一个)

 

一、什么是代理?

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

代理模式UML图:

简单结构示意图:

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。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的静态方法
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、调用处理器实现类(有木有感觉这里就是传说中的AOP啊)

  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. * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
  15. * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
  16. * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
  17. */
  18. InvocationHandler handler = new InvocationHandlerImpl(realSubject);
  19. ClassLoader loader = handler.getClass().getClassLoader();
  20. Class[] interfaces = realSubject.getClass().getInterfaces();
  21. /**
  22. * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
  23. */
  24. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
  25. System.out.println("动态代理对象的类型:"+subject.getClass().getName());
  26. String hello = subject.SayHello("jiankunking");
  27. System.out.println(hello);
  28. //        String goodbye = subject.SayGoodBye();
  29. //        System.out.println(goodbye);
  30. }
  31. }

5、输出结果如下:

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

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

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

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

也就是说,当代码执行到:
subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?
 
======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================
以下代码来自:JDK1.8.0_92
既然生成代理对象是用的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<Void>() {
  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<ClassLoader, Class<?>[], 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<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  22. if (valuesMap == null) {
  23. //putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入
  24. ConcurrentMap<Object, Supplier<V>> 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<V> stored by that
  32. // subKey from valuesMap
  33. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  34. Supplier<V> supplier = valuesMap.get(subKey);
  35. Factory factory = null;
  36. while (true) {
  37. if (supplier != null) {
  38. // supplier might be a Factory or a CacheValue<V> 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<V> 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<V> 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<ClassLoader, Class<?>[], 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<Class<?>, 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. public ProxySubject(InvocationHandler paramInvocationHandler)
  16. {
  17. super(paramInvocationHandler);
  18. }
  19. public final boolean equals(Object paramObject)
  20. {
  21. try
  22. {
  23. return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  24. }
  25. catch (Error|RuntimeException localError)
  26. {
  27. throw localError;
  28. }
  29. catch (Throwable localThrowable)
  30. {
  31. throw new UndeclaredThrowableException(localThrowable);
  32. }
  33. }
  34. public final String SayGoodBye()
  35. {
  36. try
  37. {
  38. return (String)this.h.invoke(this, m3, null);
  39. }
  40. catch (Error|RuntimeException localError)
  41. {
  42. throw localError;
  43. }
  44. catch (Throwable localThrowable)
  45. {
  46. throw new UndeclaredThrowableException(localThrowable);
  47. }
  48. }
  49. public final String SayHello(String paramString)
  50. {
  51. try
  52. {
  53. return (String)this.h.invoke(this, m4, new Object[] { paramString });
  54. }
  55. catch (Error|RuntimeException localError)
  56. {
  57. throw localError;
  58. }
  59. catch (Throwable localThrowable)
  60. {
  61. throw new UndeclaredThrowableException(localThrowable);
  62. }
  63. }
  64. public final String toString()
  65. {
  66. try
  67. {
  68. return (String)this.h.invoke(this, m2, null);
  69. }
  70. catch (Error|RuntimeException localError)
  71. {
  72. throw localError;
  73. }
  74. catch (Throwable localThrowable)
  75. {
  76. throw new UndeclaredThrowableException(localThrowable);
  77. }
  78. }
  79. public final int hashCode()
  80. {
  81. try
  82. {
  83. return ((Integer)this.h.invoke(this, m0, null)).intValue();
  84. }
  85. catch (Error|RuntimeException localError)
  86. {
  87. throw localError;
  88. }
  89. catch (Throwable localThrowable)
  90. {
  91. throw new UndeclaredThrowableException(localThrowable);
  92. }
  93. }
  94. static
  95. {
  96. try
  97. {
  98. m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
  99. m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);
  100. m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") });
  101. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  102. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  103. return;
  104. }
  105. catch (NoSuchMethodException localNoSuchMethodException)
  106. {
  107. throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  108. }
  109. catch (ClassNotFoundException localClassNotFoundException)
  110. {
  111. throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  112. }
  113. }
  114. }

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

  1. Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
这里的subject实际是这个类的一个实例,那么我们调用它的:
  1. public final String SayHello(String paramString)
就是调用我们定义的InvocationHandlerImpl的 invoke方法:
======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================

五、结论

到了这里,终于解答了:
subject.SayHello("jiankunking")这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?

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

包含生成本地class文件的demo:http://download.csdn.net/detail/xunzaosiyecao/9597474
通过分析代码可以看出Java 动态代理,具体有如下四步骤:
  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
 
本文参考过:

Java JDK 动态代理使用及实现原理分析的更多相关文章

  1. Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理

    Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理 JDK动态代理的实现及原理 作者:二青 邮箱:xtfggef@gmail.com     微博:http://weibo.com/xtfg ...

  2. Java JDK 动态代理实现和代码分析

    JDK 动态代理 内容 一.动态代理解析 1. 代理模式 2. 为什么要使用动态代理 3. JDK 动态代理简单结构图 4. JDK 动态代理实现步骤 5. JDK 动态代理 API 5.1 java ...

  3. Java,JDK动态代理的原理分析

    1. 代理基本概念: 以下是代理概念的百度解释:代理(百度百科) 总之一句话:三个元素,数据--->代理对象--->真实对象:复杂一点的可以理解为五个元素:输入数据--->代理对象- ...

  4. java jdk动态代理模式举例浅析

    代理模式概述 代理模式是为了提供额外或不同的操作,而插入的用来替代”实际”对象的对象,这些操作涉及到与”实际”对象的通信,因此代理通常充当中间人角色. java中常用的动态代理模式为jdk动态代理和c ...

  5. java jdk动态代理学习记录

    转载自: https://www.jianshu.com/p/3616c70cb37b JDK自带的动态代理主要是指,实现了InvocationHandler接口的类,会继承一个invoke方法,通过 ...

  6. java jdk动态代理

    在面试的时候面试题里有一道jdk的动态代理是原理,并给一个事例直接写代码出来,现在再整理一下 jdk动态代理主要是想动态在代码中增加一些功能,不影响现有代码,实现动态代理需要做如下几个操作 1.首先必 ...

  7. JDK动态代理的实现及原理

    Proxy.newProxyInstance(classloader,Class,invocationHandler) 调用getProxyClass0(loader, interfaces)生成代理 ...

  8. Java JDK动态代理解析

    动态代理虽不常自己实现,但在Spring或MyBatis中都有重要应用.动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问.Spring常JDK和CGLIB动态代理 ...

  9. Java JDK 动态代理(AOP)使用及实现原理分析

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

随机推荐

  1. How can I retrieve the remote git address of a repo?

    When you want to show an URL of remote branches, try: git remote -v

  2. h5上滑刷新(分页)

    $('.dom').append('<div class="loadingwrap" id="loading" style="display:n ...

  3. Intel微处理器学习笔记(五) 中断

    ▼ 中断是一个由硬件激发的过程,它中断当前正在执行的任何程序. ▼ 在Intel系列微处理器中,包括INTR和NMI(Non Maskable Interrupt)两个申请中断的引脚和一个响应INTR ...

  4. [转] Java内部类详解

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  5. NPN&PNP

    一.晶体管基础知识 晶体管分2种:NPN.PNP 晶体管通常封装为TO-92,下面是元件实物图 和 元件符合: NPN: 当电压和电流被加到基极上时,NPN晶体管: 其工作原理: 就像水龙头—给控制开 ...

  6. iOS - ImageCache 网络图片缓存

    1.ImageCache 使用内存缓存方式: 使用沙盒缓存方式: 使用网络图片第三方库方式: SDWebImage: iOS 中著名的网络图片处理框架 包含的功能:图片下载.图片缓存.下载进度监听.g ...

  7. c++操作io常见命令

    用c++练习下 系统常见io命令. 1)显示文档的文本 2)统计文本单词数字 3)列出目录所有文件 ,递归思路 4)查找第一个匹配的字符. 5)文本单词排序, 快速排序,其实还是递归思路 6)文本单词 ...

  8. Make 教程

    Make 命令教程 原文作者: 阮一峰 原文链接:http://www.ruanyifeng.com/blog/2015/02/make.html (在原文基础上稍作修改) 代码变成可执行文件,叫做编 ...

  9. Java Ant build.xml详解

    1,什么是antant是构建工具2,什么是构建概念到处可查到,形象来说,你要把代码从某个地方拿来,编译,再拷贝到某个地方去等等操作,当然不仅与此,但是主要用来干这个3,ant的好处跨平台   --因为 ...

  10. centos 解压rar文件

    默认情况下centos是不支持winrar的解压与打包的,需要安装winrar的linux版本程序 首先得下载解压软件 wget http://www.rarsoft.com/rar/rarlinux ...