likes
comments
collection
share

深入Java动态代理源码

作者站长头像
站长
· 阅读数 28

背景介绍

什么是动态代理? 动态代理,本质上还是代理模式,只不过代理类是在JDK内部产生并创建实例(字节码编辑)。 再者其内部还维护了一个基于弱引用的缓存结构。总结来说:动态代理 = 代理模式 + 字节码编辑 + 弱引用缓存。

我们来探究一下这个过程。

原理探究

示例代码:

public class TestProxy {
    interface Hello {
        void hello();
    }

    private static class HelloImpl implements Hello {
        @Override
        public void hello() {
            System.out.println("hello");
        }
    }

    public static void main(String[] args) {
        Hello hello = new HelloImpl();
        Class<? extends Hello> clazz = hello.getClass();

        Hello proxy = (Hello)Proxy.newProxyInstance(clazz.getClassLoader(),
                clazz.getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //
                        String name = method.getName();
                        if ("hello".equals(name)) {
                            //
                            System.out.println("xxx");
                        }
                        return null;
                    }
                });
        proxy.hello();
    }
}

调用关系:

深入Java动态代理源码

弱引用WeakReference

WeakCache基于弱引用的缓存结构。 构造如下:

public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                 BiFunction<K, P, V> valueFactory) {
    this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
    this.valueFactory = Objects.requireNonNull(valueFactory);
}

其中的subKeyFactory为Proxy.KeyFactory;valueFactory为Proxy.ProxyClassFactory。二者都实现了BiFunction接口,简单工厂的实现。

核心数据结构:

private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
    = new ConcurrentHashMap<>();

两层Map的结构: 第一层的key:CacheKey类型,继承WeakReference,使用其valueOf()创建实例(简单工厂模式)。 第一层的value:Map结构,即第二层。

第二层的key:类型可以为:Key1 Key2 KeyN 和Object(key0),不一定会继承WeakReference。通过subKeyFactory创建对象。 第二层的value:CacheValue类型,继承WeakReference,使用构造方法创建,参数为valueFactory创建的对象。

简单工厂+函数接口

Proxy.KeyFactory和Proxy.ProxyClassFactory都是简单工厂,分别用于创建key和value对象;其实现BiFunction接口,以BiFunction的apply()作为工厂的方法。

字节码编辑技术

ProxyGenerator#generateProxyClass()是基于字节码编辑技术直接产生字节码,我我们可以通过如下代码,反编译产看一下生成的class文件的源代码:

测试代码:

byte[] bytes = ProxyGenerator.generateProxyClass("xxx$Proxy", clazz.getInterfaces(), 16);
Path path = Paths.get("/Users/xwei/Desktop/Proxy.class");
try {
    Files.createFile(path);
    OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.WRITE);
    outputStream.write(bytes);
    outputStream.close();
} catch (IOException e) {
    e.printStackTrace();
}

反编译之后的代理类的源代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.proxy.TestProxy.Hello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class xxx$Proxy extends Proxy implements Hello {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public xxx$Proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void hello() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.proxy.TestProxy$Hello").getMethod("hello");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}