JDK 动态代理

Demo

对于被代理的接口类,Proxy 会保证只有一个,但是它的实例会有多个,每个实例都会有对应的 InvocationHandler

Proxy 的 API
image.png

  1. // If the proxy class defined by the given loader implementing
  2. // the given interfaces exists, this will simply return the cached copy;
  3. // otherwise, it will create the proxy class via the ProxyClassFactory

输出被代理的 Class 到文件:

  1. Class<?> proxyClass = Proxy.getProxyClass(Invoker.class.getClassLoader(), Invoker.class);
  2. Files.write(new File("ProxyClazz.class").toPath(), ProxyGenerator.generateProxyClass("ProxyClazz", proxyClass.getInterfaces()));

ProxyGenerator 会根据传入的接口,找到其对应的 Proxy 的实现类,由于 Proxy 保证的唯一性,所以只会存在一个

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

使用 Evaluate Expression,将动态代理类输出到文件:


Proxy 类中使用了 WeakCache 作为 Class 的缓存:
Key 和 Value 也分别使用了其内部类(工厂类)
而 ProxyClassFactory 中使用了 ProxyGenerator.generateProxyClass() 来创建代理类,ProxyGenerator 中是使用字节流的方式进行类的动态生成。

public class Proxy implements java.io.Serializable {
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }
}

TODO

  1. 想办法把 Class 变成 byte[] 或者直接输出成文件(拦截 defineClass0?或者使用 javaagent)
    1. 不知道动态生成的 class 会不会被 javaagent 拦截
  2. byte[] -> Class 记笔记

CGLib

ClassLoadingMXBean、Enhancer

// 测试元空间 OOM
public static void main(String[] args) {
    ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
    while (true) {
        // 设置增强类信息
        Enhancer enhancer = new Enhancer();
        // 被增强的类
        enhancer.setSuperclass(Hello.class);
        enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class});
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                return 1;
            }

            @Override
            public boolean equals(Object obj) {
                return super.equals(obj);
            }
        });

        Class clazz = enhancer.createClass();
        System.out.println(clazz.getName());
        //显示数量信息(共加载过的类型数目,当前还有效的类型数目,已经被卸载的类型数目)
        System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
        System.out.println("active: " + loadingBean.getLoadedClassCount());
        System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
    }
}