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. 3.mybatis注解

    在上篇2.mybatis入门实例(一) 连接数据库进行查询的基础上 1.添加Mapper接口:UserMapper接口,并使用mybatis的注解 import java.util.List; imp ...

  2. HTTP协议(转自:小坦克博客)

    原文地址:http://www.cnblogs.com/TankXiao/archive/2012/02/13/2342672.html HTTP协议详解 当今web程序的开发技术真是百家争鸣,ASP ...

  3. HttpServletRequest学习

    package cn.request; import java.io.IOException; import java.io.PrintWriter; import java.io.Unsupport ...

  4. [转载] TCP协议缺陷不完全记录

    原文: http://www.blogjava.net/yongboy/archive/2015/05/07/424917.html tcp是一个非常复杂并且古老的协议, 之前教科书上将的很多东西应用 ...

  5. 百度之星Astar2016 Round2A

    All X 等比数列求和一下 A/B MOD C = A MOD (B*C) / B  或者分治一下 Sitting in Line 状压+拓扑dp dp(i, j)表示当前二进制状态为j,当前状态的 ...

  6. 加速Eclipse使其成为超快的IDE

    按照下述步骤来加速Eclipse为超快的IDE,它适用于32和64位版本的Eclipse /JDK(OS为64位Windows 7). 1.禁用防病毒软件,或将JDK.Eclipse.workspac ...

  7. @requestBody注解的使用

    1.@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是ap ...

  8. OpenGL的glTexCoord2f纹理坐标配置

    纹理坐标配置函数,先看定义: void glTexCoord2f (GLfloat s, GLfloat t); 1.glTexCoord2f()函数 有两个参数:GLfloat s, GLfloat ...

  9. linux mount命令的用法详细解析

    挂接命令(mount)首先,介绍一下挂接(mount)命令的使用方法,mount命令参数非常多,这里主要讲一下今天我们要用到的.命令格式:mount [-t vfstype] [-o options] ...

  10. Spring MVC 数据绑定(四)

        Spring支持多种形式的类型绑定,包括: 1.基本数据类型.String和String[] 2.简单对象类型 3.List类型 4.Set类型 5.Map类型 6.复合数据类型     接下 ...