介绍

Spring动态代理可以选择使用jdk动态代理, 或者cglib动态代理, jdk动态代理位于 java.lang.reflect 包下.
使用时涉及
接口: java.lang.reflect.InvocationHandler
动态代理类: java.lang.reflect.Proxy
注意: JDK 动态代理是基于接口的代理, 只能对实现接口的类生成代理, 不能对类进行代理

使用步骤

1.创建InvocationHandler接口的实现类, 并编写invoke方法的实现
2.创建被代理类的接口及实现类
3.使用动态代理类Proxy的静态方法生成代理类实例
4.使用实例调用方法

代码演示

按照步骤编写简易逻辑代码.

创建InvocationHandler接口的实现类

  1. /**
  2. * JDK 动态代理
  3. * 基于接口的代理, 只能对实现接口的类生成代理, 不能对类进行代理
  4. *
  5. * @author liuzhihang
  6. * @date 2018/5/17 10:36
  7. */
  8. public class MyInvocationHandler implements InvocationHandler {
  9. /**
  10. * 目标对象
  11. */
  12. private Object target;
  13. public MyInvocationHandler(Object target) {
  14. this.target = target;
  15. }
  16. @Override
  17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  18. System.out.println("jdk 动态代理 before . . . ");
  19. System.out.println("当前代理方法为:" + method);
  20. Object invoke = method.invoke(target, args);
  21. System.out.println("jdk 动态代理 after . . . ");
  22. return invoke;
  23. }
  24. }

创建被代理类的接口及实现类

  1. /**
  2. * 被代理类的接口
  3. * @author liuzhihang
  4. * @date 2018/5/17 10:47
  5. */
  6. public interface Subject {
  7. /**
  8. * 获取名字
  9. * @return
  10. */
  11. String getName();
  12. /**
  13. * 获取年龄
  14. * @param name
  15. * @return
  16. */
  17. String getAge(String name);
  18. }
  1. /**
  2. * 被代理类
  3. *
  4. * @author liuzhihang
  5. * @date 2018/5/17 10:48
  6. */
  7. public class SubjectImpl implements Subject {
  8. @Override
  9. public String getName() {
  10. System.out.println("SubjectImpl的获取名字方法 . . .");
  11. return "liuzhihang";
  12. }
  13. @Override
  14. public String getAge(String name) {
  15. System.out.println(name + "开始获取年龄 . . .");
  16. return "25";
  17. }
  18. }

使用动态代理类Proxy的静态方法生成代理类实例

获取代理类实例有以下两种方式, 一种是通过Proxy.newProxyInstance(..)获取, 一种是通过 Proxy.getProxyClass(..) 方式获取
1.Proxy.newProxyInstance(..)

  1. /**
  2. * 当代理类实例调用方法时, 会自动跳转到代理类关联的 handler 对象, 通过 method.invoke(target, args) 进行调用
  3. *
  4. *
  5. * @author liuzhihang
  6. * @date 2018/5/17 10:49
  7. */
  8. public class ProxyMainTest {
  9. public static void main(String[] args) {
  10. Subject subject = new SubjectImpl();
  11. ClassLoader classLoader = subject.getClass().getClassLoader();
  12. Class<?>[] interfaces = subject.getClass().getInterfaces();
  13. MyInvocationHandler handler = new MyInvocationHandler(subject);
  14. // 生成代理类实例
  15. Subject proxyInstance = (Subject) Proxy.newProxyInstance(classLoader, interfaces, handler);
  16. String name = proxyInstance.getName();
  17. String instanceAge = proxyInstance.getAge("liuzhihang");
  18. System.err.println(name + " " + instanceAge);
  19. }
  20. }

2.Proxy.getProxyClass(..)

  1. /**
  2. * 当代理类实例调用方法时, 会自动跳转到代理类关联的 handler 对象, 通过 method.invoke(target, args) 进行调用
  3. * 此方式有异常抛出
  4. *
  5. * @author liuzhihang
  6. * @date 2018/5/17 10:49
  7. */
  8. public class ProxyMainTest {
  9. public static void main(String[] args) {
  10. try {
  11. Subject subject = new SubjectImpl();
  12. ClassLoader classLoader = subject.getClass().getClassLoader();
  13. Class<?>[] interfaces = subject.getClass().getInterfaces();
  14. MyInvocationHandler handler = new MyInvocationHandler(subject);
  15. Class<?> proxyClass = Proxy.getProxyClass(classLoader, interfaces);
  16. Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
  17. Subject subject1 = (Subject) constructor.newInstance(handler);
  18. String name1 = subject1.getName();
  19. String instanceAge1 = subject1.getAge("liuzhihang");
  20. System.err.println(name1 + " " + instanceAge1);
  21. } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

执行结果

  1. D:\jdk1.8\bin\java.exe . . .
  2. liuzhihang 25
  3. jdk 动态代理 before . . .
  4. 当前代理方法为:public abstract java.lang.String com.liuzhihang.tool.proxy.jdk.Subject.getName()
  5. SubjectImpl的获取名字方法 . . .
  6. jdk 动态代理 after . . .
  7. jdk 动态代理 before . . .
  8. 当前代理方法为:public abstract java.lang.String com.liuzhihang.tool.proxy.jdk.Subject.getAge(java.lang.String)
  9. liuzhihang开始获取年龄 . . .
  10. jdk 动态代理 after . . .
  11. Process finished with exit code 0

结论: 代理实例在每次调用方法是都会通过代理类进行调用

相关源码解析

完整注释可自己查看相关源码, 源码过程应当DeBug多走走.
1.调用 Proxy.newProxyInstance 方法

  1. /**
  2. * 返回指定接口的代理类实例,该接口将方法调用分派给指定的调用处理程序
  3. */
  4. @CallerSensitive
  5. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  6. // 非空校验
  7. Objects.requireNonNull(h);
  8. final Class<?>[] intfs = interfaces.clone();
  9. // 获取系统安全接口
  10. final SecurityManager sm = System.getSecurityManager();
  11. if (sm != null) {
  12. // 校验权限
  13. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  14. }
  15. /*
  16. * 从缓存中获取代理类 或者 生成新的代理类
  17. */
  18. Class<?> cl = getProxyClass0(loader, intfs);
  19. /*
  20. * 通过反射获取构造函数对象并生成代理类实例
  21. */
  22. try {
  23. if (sm != null) {
  24. checkNewProxyPermission(Reflection.getCallerClass(), cl);
  25. }
  26. // 获取构造
  27. final Constructor<?> cons = cl.getConstructor(constructorParams);
  28. final InvocationHandler ih = h;
  29. // 验证代理类的修饰符
  30. if (!Modifier.isPublic(cl.getModifiers())) {
  31. // 修改访问权限
  32. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  33. public Void run() {
  34. // 将此对象的可访问标志设置为指定的布尔值, true表示反射对象在使用时应禁止Java语言访问检查, false表示反射对象应强制执行Java语言访问检查
  35. cons.setAccessible(true);
  36. return null;
  37. }
  38. });
  39. }
  40. //生成实例, 并将参数传入构造
  41. return cons.newInstance(new Object[]{h});
  42. } catch (IllegalAccessException | InstantiationException e) {
  43. throw new InternalError(e.toString(), e);
  44. } catch (InvocationTargetException e) {
  45. Throwable t = e.getCause();
  46. if (t instanceof RuntimeException) {
  47. throw (RuntimeException) t;
  48. } else {
  49. throw new InternalError(t.toString(), t);
  50. }
  51. } catch (NoSuchMethodException e) {
  52. throw new InternalError(e.toString(), e);
  53. }
  54. }

可以看出获取代理类是在 Class<?> cl = getProxyClass0(loader, intfs); 处, 继续相关逻辑
2.获取代理类相关逻辑

  1. /**
  2. * 生成代理类, 之前必须进行权限检查
  3. */
  4. private static Class<?> getProxyClass0(ClassLoader loader,
  5. Class<?>... interfaces) {
  6. if (interfaces.length > 65535) {
  7. throw new IllegalArgumentException("interface limit exceeded");
  8. }
  9. //如果由实现给定接口的给定加载器定义的代理类存在,则它将简单地返回缓存副本; 否则,它将通过Proxy Class Factory创建代理类
  10. return proxyClassCache.get(loader, interfaces);
  11. }

3.proxyClassCache.get(loader, interfaces);
java.lang.reflect.WeakCache#get(..) 介绍

  1. /**
  2. * 通过缓存查找值, 如果缓存中没有给定的(key,sub Key)对的条目或条目已被清除,则它总是评估{Key sub Key Factory}函数并可选择评估{Factory value}函数
  3. */
  4. public V get(K key, P parameter) {
  5. // 非空校验
  6. Objects.requireNonNull(parameter);
  7. // 判断移除队列
  8. expungeStaleEntries();
  9. // 缓存key
  10. Object cacheKey = CacheKey.valueOf(key, refQueue);
  11. // 延迟加载使用二级map
  12. ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  13. if (valuesMap == null) {
  14. ConcurrentMap<Object, Supplier<V>> oldValuesMap
  15. = map.putIfAbsent(cacheKey,
  16. valuesMap = new ConcurrentHashMap<>());
  17. if (oldValuesMap != null) {
  18. valuesMap = oldValuesMap;
  19. }
  20. }
  21. // 创建子key 并根据key 检索supplier
  22. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  23. // 根据key获取supplier
  24. Supplier<V> supplier = valuesMap.get(subKey);
  25. Factory factory = null;
  26. while (true) {
  27. if (supplier != null) {
  28. // supplier 可能为 Factory 或者 CacheValue<V> 的实例, 从缓存中获取到则直接返回
  29. V value = supplier.get();
  30. if (value != null) {
  31. return value;
  32. }
  33. }
  34. // factory不存在则创建
  35. if (factory == null) {
  36. factory = new Factory(key, parameter, subKey, valuesMap);
  37. }
  38. // supplier 为null
  39. if (supplier == null) {
  40. // 从valuesMap获取supplier
  41. supplier = valuesMap.putIfAbsent(subKey, factory);
  42. if (supplier == null) {
  43. // successfully installed Factory
  44. supplier = factory;
  45. }
  46. // else retry with winning supplier
  47. } else {
  48. if (valuesMap.replace(subKey, supplier, factory)) {
  49. // successfully replaced
  50. // cleared CacheEntry / unsuccessful Factory
  51. // with our Factory
  52. supplier = factory;
  53. } else {
  54. // retry with current supplier
  55. supplier = valuesMap.get(subKey);
  56. }
  57. }
  58. }
  59. }

可以发现重点在 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); 获取 subKey 的过程中.
4.subKeyFactory.apply(key, parameter)
Debug发现在此处调用的是 java.lang.reflect.Proxy.ProxyClassFactory 静态内部类,
此处根据接口的数量生成二级缓存

  1. /**
  2. * 一个工厂函数, 用于生成, 定义并返回给定ClassLoader和接口数组的代理类
  3. */
  4. private static final class ProxyClassFactory
  5. implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  6. {
  7. // 所有代理类的前缀
  8. private static final String proxyClassNamePrefix = "$Proxy";
  9. // next number to use for generation of unique proxy class names
  10. private static final AtomicLong nextUniqueNumber = new AtomicLong();
  11. @Override
  12. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  13. // 在IdentityHashMap中, 当且仅当两个key严格相等(key1==key2)时,IdentityHashMap才认为两个key相等
  14. Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  15. // 循环接口数组
  16. for (Class<?> intf : interfaces) {
  17. /*
  18. * 验证类加载器是否将此接口的名称解析为同一个Class对象
  19. */
  20. Class<?> interfaceClass = null;
  21. try {
  22. // 获取接口的 class
  23. interfaceClass = Class.forName(intf.getName(), false, loader);
  24. } catch (ClassNotFoundException e) {
  25. }
  26. if (interfaceClass != intf) {
  27. throw new IllegalArgumentException(
  28. intf + " is not visible from class loader");
  29. }
  30. /*
  31. * 验证interfaceClass是否为接口
  32. */
  33. if (!interfaceClass.isInterface()) {
  34. throw new IllegalArgumentException(
  35. interfaceClass.getName() + " is not an interface");
  36. }
  37. /*
  38. * 验证接口是否重复
  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. * 验证所有非公开代理接口是否在同一个包中
  49. */
  50. for (Class<?> intf : interfaces) {
  51. int flags = intf.getModifiers();
  52. if (!Modifier.isPublic(flags)) {
  53. accessFlags = Modifier.FINAL;
  54. String name = intf.getName();
  55. int n = name.lastIndexOf('.');
  56. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  57. if (proxyPkg == null) {
  58. proxyPkg = pkg;
  59. } else if (!pkg.equals(proxyPkg)) {
  60. throw new IllegalArgumentException(
  61. "non-public interfaces from different packages");
  62. }
  63. }
  64. }
  65. if (proxyPkg == null) {
  66. // 如果没有非公开的代理接口,使用 com.sun.proxy package
  67. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  68. }
  69. /*
  70. * 为要生成的代理类选择一个名称
  71. */
  72. long num = nextUniqueNumber.getAndIncrement();
  73. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  74. /*
  75. * 生成代理类
  76. */
  77. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
  78. try {
  79. return defineClass0(loader, proxyName,
  80. proxyClassFile, 0, proxyClassFile.length);
  81. } catch (ClassFormatError e) {
  82. /*
  83. * A ClassFormatError here means that (barring bugs in the
  84. * proxy class generation code) there was some other
  85. * invalid aspect of the arguments supplied to the proxy
  86. * class creation (such as virtual machine limitations
  87. * exceeded).
  88. */
  89. throw new IllegalArgumentException(e.toString());
  90. }
  91. }
  92. }

5.生辰给代理类
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
可以在测试类中添加以下内容打印出代理类:

  1. System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

代理类内容如下:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package com.sun.proxy;
  6. import com.liuzhihang.tool.proxy.jdk.Subject;
  7. import java.lang.reflect.InvocationHandler;
  8. import java.lang.reflect.Method;
  9. import java.lang.reflect.Proxy;
  10. import java.lang.reflect.UndeclaredThrowableException;
  11. public final class $Proxy0 extends Proxy implements Subject {
  12. private static Method m1;
  13. private static Method m3;
  14. private static Method m2;
  15. private static Method m4;
  16. private static Method m0;
  17. public $Proxy0(InvocationHandler var1) throws {
  18. super(var1);
  19. }
  20. public final boolean equals(Object var1) throws {
  21. try {
  22. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  23. } catch (RuntimeException | Error var3) {
  24. throw var3;
  25. } catch (Throwable var4) {
  26. throw new UndeclaredThrowableException(var4);
  27. }
  28. }
  29. public final String getName() throws {
  30. try {
  31. return (String)super.h.invoke(this, m3, (Object[])null);
  32. } catch (RuntimeException | Error var2) {
  33. throw var2;
  34. } catch (Throwable var3) {
  35. throw new UndeclaredThrowableException(var3);
  36. }
  37. }
  38. public final String toString() throws {
  39. try {
  40. return (String)super.h.invoke(this, m2, (Object[])null);
  41. } catch (RuntimeException | Error var2) {
  42. throw var2;
  43. } catch (Throwable var3) {
  44. throw new UndeclaredThrowableException(var3);
  45. }
  46. }
  47. public final String getAge(String var1) throws {
  48. try {
  49. return (String)super.h.invoke(this, m4, new Object[]{var1});
  50. } catch (RuntimeException | Error var3) {
  51. throw var3;
  52. } catch (Throwable var4) {
  53. throw new UndeclaredThrowableException(var4);
  54. }
  55. }
  56. public final int hashCode() throws {
  57. try {
  58. return (Integer)super.h.invoke(this, m0, (Object[])null);
  59. } catch (RuntimeException | Error var2) {
  60. throw var2;
  61. } catch (Throwable var3) {
  62. throw new UndeclaredThrowableException(var3);
  63. }
  64. }
  65. static {
  66. try {
  67. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  68. m3 = Class.forName("com.liuzhihang.tool.proxy.jdk.Subject").getMethod("getName");
  69. m2 = Class.forName("java.lang.Object").getMethod("toString");
  70. m4 = Class.forName("com.liuzhihang.tool.proxy.jdk.Subject").getMethod("getAge", Class.forName("java.lang.String"));
  71. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  72. } catch (NoSuchMethodException var2) {
  73. throw new NoSuchMethodError(var2.getMessage());
  74. } catch (ClassNotFoundException var3) {
  75. throw new NoClassDefFoundError(var3.getMessage());
  76. }
  77. }
  78. }

可以看出生成的$Proxy0类继承Proxy动态代理类并实现了Subject被代理接口, 实现所有方法
通过 super.h.invoke(this, m1, new Object[]{var1}) 内部调用了 InvocationHandler.invoke(…)方法, 通过反射调用代理实例的方法