[关闭]
@coldxiangyu 2017-06-15T16:23:24.000000Z 字数 10876 阅读 1134

源码之:java动态代理

源码系列


关于代理模式这里就不再详述了。

在编写简易的RPC以及AOP框架过程中,涉及到了使用java动态代理(Proxy)。
我们来首先来看java动态代理的简易demo:
1.定义接口Subject

  1. package com.lxy.dynamicproxy;
  2. /**
  3. * Created by coldxiangyu on 2017/6/15.
  4. */
  5. public interface Subject {
  6. public void request();
  7. }

2.定义真实角色类

  1. package com.lxy.dynamicproxy;
  2. /**
  3. * Created by coldxiangyu on 2017/6/15.
  4. */
  5. public class RealSubject implements Subject {
  6. @Override
  7. public void request() {
  8. System.out.println("this is real subject");
  9. }
  10. }

3.定义代理类DynamicSubject实现InvocationHandler接口,重写invoke方法:

  1. import java.lang.reflect.Method;
  2. /**
  3. * Created by coldxiangyu on 2017/6/15.
  4. */
  5. public class DynamicSubject implements InvocationHandler{
  6. private Object obj;
  7. public DynamicSubject(Object obj){
  8. this.obj = obj;
  9. }
  10. @Override
  11. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  12. System.out.println("before calling:" + method);
  13. System.out.println("before calling:" + method);
  14. return method.invoke(obj, args);
  15. }
  16. }

4.客户端通过Proxy.newProxyInstance调用:

  1. package com.lxy.dynamicproxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Proxy;
  4. /**
  5. * Created by coldxiangyu on 2017/6/15.
  6. */
  7. public class Client {
  8. public static void main(String[] args){
  9. Subject rs = new RealSubject();
  10. InvocationHandler ds = new DynamicSubject(rs);
  11. Class cls = rs.getClass();
  12. Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds);
  13. subject.request();
  14. }
  15. }

调用结果:

  1. before calling:public abstract void com.lxy.dynamicproxy.Subject.request()
  2. before calling:public abstract void com.lxy.dynamicproxy.Subject.request()
  3. this is real subject
  4. 进程已结束,退出代码0

我们来看一下源码(我本地JDK1.8)是怎样的,一个是InvocationHandler接口,另一个就是Proxy类。
InvocationHandler接口比较简单,只定义了一个返回类型是Object的方法:public Object invoke(Object proxy, Method method, Object[] args),那么这个方法必然是在Proxy类中存在调用的,带着这个猜测我们去看Proxy类:
Proxy类就复杂多了,我们挑主要的地方看,首先看我们调用的Proxy.newProxyInstance方法:

  1. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  2. //Objects.requireNonNull 判空方法,之后所有的单纯的判断null并抛异常,都是此方法
  3. Objects.requireNonNull(h);
  4. //clone 类实现的所有接口
  5. final Class<?>[] intfs = interfaces.clone();
  6. //获取当前系统安全接口
  7. final SecurityManager sm = System.getSecurityManager();
  8. if (sm != null) {
  9. //Reflection.getCallerClass返回调用该方法的方法的调用类;loader:接口的类加载器
  10. //进行包访问权限、类加载器权限等检查
  11. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  12. }
  13. /*
  14. * Look up or generate the designated proxy class.
  15. * 查找或生成代理类
  16. */
  17. Class<?> cl = getProxyClass0(loader, intfs);
  18. /*
  19. * Invoke its constructor with the designated invocation handler.
  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. if (!Modifier.isPublic(cl.getModifiers())) {
  30. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  31. public Void run() {
  32. cons.setAccessible(true);
  33. return null;
  34. }
  35. });
  36. }
  37. //返回 代理对象
  38. return cons.newInstance(new Object[]{h});
  39. } catch (IllegalAccessException|InstantiationException e) {
  40. throw new InternalError(e.toString(), e);
  41. } catch (InvocationTargetException e) {
  42. Throwable t = e.getCause();
  43. if (t instanceof RuntimeException) {
  44. throw (RuntimeException) t;
  45. } else {
  46. throw new InternalError(t.toString(), t);
  47. }
  48. } catch (NoSuchMethodException e) {
  49. throw new InternalError(e.toString(), e);
  50. }
  51. }

从上面的源码可以看出,newProxyInstance主要通过getProxyClass0(loader, intfs)方法生成代理类,并通过getConstructor(constructorParams)获取构造方法,最后通过cons.newInstance(new Object[]{h})返回代理类对象。
我们再来看看getProxyClass0是如何获取代理类的:

  1. /**
  2. * a cache of proxy classes:动态代理类的弱缓存容器
  3. * KeyFactory:根据接口的数量,映射一个最佳的key生成函数,其中表示接口的类对象被弱引用;也就是key对象被弱引用继承自WeakReference(key0、key1、key2、keyX),保存接口密钥(hash值)
  4. * ProxyClassFactory:生成动态类的工厂
  5. * 注意,两个都实现了BiFunction<ClassLoader, Class<?>[], Object>接口
  6. */
  7. private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  8. /**
  9. * Generate a proxy class. Must call the checkProxyAccess method
  10. * to perform permission checks before calling this.
  11. * 生成代理类,调用前必须进行 checkProxyAccess权限检查,所以newProxyInstance进行了权限检查
  12. */
  13. private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
  14. //实现接口的最大数量<65535;
  15. if (interfaces.length > 65535) {
  16. throw new IllegalArgumentException("interface limit exceeded");
  17. }
  18. // If the proxy class defined by the given loader implementing
  19. // the given interfaces exists, this will simply return the cached copy;
  20. // otherwise, it will create the proxy class via the ProxyClassFactory
  21. // 如果缓存中有,就直接返回,否则会生成
  22. return proxyClassCache.get(loader, interfaces);
  23. }

这个方法并没有太多有效信息,我们继续跳转proxyClassCache.get(loader, interfaces)方法:

  1. public V get(K key, P parameter) {
  2. //key:类加载器;parameter:接口数组
  3. Objects.requireNonNull(parameter);
  4. //清除已经被GC回收的弱引用
  5. expungeStaleEntries();
  6. //CacheKey弱引用类,refQueue已经被回收的弱引用队列;构建一个CacheKey
  7. Object cacheKey = CacheKey.valueOf(key, refQueue);
  8. //map一级缓存,获取valuesMap二级缓存
  9. ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  10. if (valuesMap == null) {
  11. ConcurrentMap<Object, Supplier<V>> oldValuesMap
  12. = map.putIfAbsent(cacheKey,
  13. valuesMap = new ConcurrentHashMap<>());
  14. if (oldValuesMap != null) {
  15. valuesMap = oldValuesMap;
  16. }
  17. }
  18. // subKeyFactory类型是KeyFactory,apply返回表示接口的key
  19. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  20. //Factory 实现了supplier,我们实际是获取缓存中的Factory,调用其get方法
  21. Supplier<V> supplier = valuesMap.get(subKey);
  22. Factory factory = null;
  23. //下面用到了 CAS+重试 实现的多线程安全的 非阻塞算法
  24. while (true) {
  25. if (supplier != null) {
  26. // 只需要知道,最终会调用get方法,此supplier可能是缓存中取出来的,也可能是Factory新new出来的
  27. V value = supplier.get();
  28. if (value != null) {
  29. return value;
  30. }
  31. }
  32. // else no supplier in cache
  33. // or a supplier that returned null (could be a cleared CacheValue
  34. // or a Factory that wasn't successful in installing the CacheValue)
  35. // lazily construct a Factory
  36. if (factory == null) {
  37. factory = new Factory(key, parameter, subKey, valuesMap);
  38. }
  39. if (supplier == null) {
  40. supplier = valuesMap.putIfAbsent(subKey, factory);
  41. if (supplier == null) {
  42. // successfully installed Factory
  43. supplier = factory;
  44. }
  45. // else retry with winning supplier
  46. } else {
  47. if (valuesMap.replace(subKey, supplier, factory)) {
  48. // successfully replaced
  49. // cleared CacheEntry / unsuccessful Factory
  50. // with our Factory
  51. supplier = factory;
  52. } else {
  53. // retry with current supplier
  54. supplier = valuesMap.get(subKey);
  55. }
  56. }
  57. }
  58. }

我们看到这个方法的返回值是通过supplier.get()获取的,这个方法调用ProxyClassFactory的apply()方法:

  1. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  2. Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  3. for (Class<?> intf : interfaces) {
  4. /*
  5. * Verify that the class loader resolves the name of this interface to the same Class object.
  6. * 类加载器和接口名解析出的是同一个
  7. */
  8. Class<?> interfaceClass = null;
  9. try {
  10. interfaceClass = Class.forName(intf.getName(), false, loader);
  11. } catch (ClassNotFoundException e) {
  12. }
  13. if (interfaceClass != intf) {
  14. throw new IllegalArgumentException( intf + " is not visible from class loader");
  15. }
  16. /*
  17. * Verify that the Class object actually represents an interface.
  18. * 确保是一个接口
  19. */
  20. if (!interfaceClass.isInterface()) {
  21. throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface");
  22. }
  23. /*
  24. * Verify that this interface is not a duplicate.
  25. * 确保接口没重复
  26. */
  27. if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
  28. throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName());
  29. }
  30. }
  31. String proxyPkg = null; // package to define proxy class in
  32. int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
  33. /*
  34. * Record the package of a non-public proxy interface so that the proxy class will be defined in the same package.
  35. * Verify that all non-public proxy interfaces are in the same package.
  36. * 验证所有非公共的接口在同一个包内;公共的就无需处理
  37. */
  38. for (Class<?> intf : interfaces) {
  39. int flags = intf.getModifiers();
  40. if (!Modifier.isPublic(flags)) {
  41. accessFlags = Modifier.FINAL;
  42. String name = intf.getName();
  43. int n = name.lastIndexOf('.');
  44. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  45. if (proxyPkg == null) {
  46. proxyPkg = pkg;
  47. } else if (!pkg.equals(proxyPkg)) {
  48. throw new IllegalArgumentException( "non-public interfaces from different packages");
  49. }
  50. }
  51. }
  52. if (proxyPkg == null) {
  53. // if no non-public proxy interfaces, use com.sun.proxy package
  54. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  55. }
  56. /*
  57. * Choose a name for the proxy class to generate.
  58. * proxyClassNamePrefix = $Proxy
  59. * nextUniqueNumber 是一个原子类,确保多线程安全,防止类名重复,类似于:$Proxy0,$Proxy1......
  60. */
  61. long num = nextUniqueNumber.getAndIncrement();
  62. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  63. /*
  64. * Generate the specified proxy class.
  65. * 生成类字节码的方法:重点
  66. */
  67. byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
  68. try {
  69. return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
  70. } catch (ClassFormatError e) {
  71. /*
  72. * A ClassFormatError here means that (barring bugs in the
  73. * proxy class generation code) there was some other
  74. * invalid aspect of the arguments supplied to the proxy
  75. * class creation (such as virtual machine limitations
  76. * exceeded).
  77. */
  78. throw new IllegalArgumentException(e.toString());
  79. }
  80. }

由此ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags),生成类的字节码:

  1. public static byte[] generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags) {
  2. ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
  3. //真正生成字节码的方法
  4. final byte[] classFile = gen.generateClassFile();
  5. //如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数
  6. //当然,也可以通过返回的bytes自己输出
  7. if (saveGeneratedFiles) {
  8. java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() {
  9. public Void run() {
  10. try {
  11. int i = name.lastIndexOf('.');
  12. Path path;
  13. if (i > 0) {
  14. Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
  15. Files.createDirectories(dir);
  16. path = dir.resolve(name.substring(i+1, name.length()) + ".class");
  17. } else {
  18. path = Paths.get(name + ".class");
  19. }
  20. Files.write(path, classFile);
  21. return null;
  22. } catch (IOException e) {
  23. throw new InternalError( "I/O exception saving generated file: " + e);
  24. }
  25. }
  26. });
  27. }
  28. return classFile;
  29. }

我们看到 final byte[] classFile = gen.generateClassFile();是真正获取字节码的方法。限于篇幅,这里就不贴如何生成字节码类文件了,有兴趣的可以自行去看。我们真正关心的是生成的字节码文件是怎样的,我们将字节码类文件反编译查看一下:

  1. final class $Proxy0 extends Proxy implements pro {
  2. //fields
  3. private static Method m1;
  4. private static Method m2;
  5. private static Method m3;
  6. private static Method m0;
  7. public $Proxy0(InvocationHandler var1) throws {
  8. super(var1);
  9. }
  10. public final boolean equals(Object var1) throws {
  11. try {
  12. return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
  13. } catch (RuntimeException | Error var3) {
  14. throw var3;
  15. } catch (Throwable var4) {
  16. throw new UndeclaredThrowableException(var4);
  17. }
  18. }
  19. public final String toString() throws {
  20. try {
  21. return (String)super.h.invoke(this, m2, (Object[])null);
  22. } catch (RuntimeException | Error var2) {
  23. throw var2;
  24. } catch (Throwable var3) {
  25. throw new UndeclaredThrowableException(var3);
  26. }
  27. }
  28. public final void text() throws {
  29. try {
  30. //实际就是调用代理类的invoke方法
  31. 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 int hashCode() throws {
  39. try {
  40. return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
  41. } catch (RuntimeException | Error var2) {
  42. throw var2;
  43. } catch (Throwable var3) {
  44. throw new UndeclaredThrowableException(var3);
  45. }
  46. }
  47. static {
  48. try {
  49. //这里每个方法对象 和类的实际方法绑定
  50. m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
  51. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  52. m3 = Class.forName("spring.commons.api.study.CreateModel.pro").getMethod("text", new Class[0]);
  53. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  54. } catch (NoSuchMethodException var2) {
  55. throw new NoSuchMethodError(var2.getMessage());
  56. } catch (ClassNotFoundException var3) {
  57. throw new NoClassDefFoundError(var3.getMessage());
  58. }
  59. }
  60. }

这时候,我们就看得很清楚了,每个方法的实现其实都是通过调用InvocationHandler的invoke方法实现的。
这时候总结一下Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds)的实现过程就是首先通过classLoaderinterfaces生成字节码代理类,再进行重新构造,生成代理对象的过程。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注