JDK 动态代理的实现

JDK 动态代理的实现

虽然在常用的 Java 框架(Spring、MyBaits 等)中,经常见到 JDK 动态代理的使用,也知道了怎么去写一个 JDK 动态代理的 Demo,但是并不清楚实现原理。

之前略微知道是先生成一个代理对象,然后外部调用代理对象的接口方法,然后代理又会调用原始对象的方法,仅此而已。现在想稍微深入一丢,了解部分实现方式。

Java 程序是运行在 JVM 中的,源码首先编译成字节码,然后加载到虚拟机中,被虚拟机解析然后执行(注意这里的措辞不一定严谨准确,会其意即可)。

JDK 动态代理实际上也就是在代码的运行中动态的生成了实现指定接口(被代理对象实现的接口)的类的字节码,对应的也就是代理类,然后创建这个代理类的对象,也就是代理对象。关于这一部分内容,看这篇博文更好,写的很详细。其实本文关注的点其实是 JDK 是如何创建代理类的,进而找到为什么调用代理对象的方法,就能增强原始对象的方法。

先上简单的 Demo 代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *
 * @author xi
 * @date 2018/08/23 12:04
 */
public class DynamicProxyTest {
    interface IHello {
        void sayHello();
    }

    static class Hello implements IHello {
        @Override
        public void sayHello() {
            System.out.println("hello world");
        }
    }

    static class DynamicProxy implements InvocationHandler {

        Object originalObj;

        Object bind(Object originalObj) {
            this.originalObj = originalObj;
            return Proxy.newProxyInstance(
                    originalObj.getClass().getClassLoader(),
                    originalObj.getClass().getInterfaces(), this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("welcome");
            return method.invoke(originalObj, args);
        }
    }

    public static void main(String[] args) {
        IHello hello = (IHello) new DynamicProxy().bind(new Hello());
        hello.sayHello();
    }
}

这个例子是『深入理解 Java 虚拟机』书上的例子,感觉例子中的DynamicProxy取名不太好,容易误导像我这样的初学者,容易把它看成代理类,实则不然,它只是个InvocationHandler接口的实现类,不要搞混了。

其实本次想要关注的重点是代理类和代理对象是如何产生的,所以要看看java.lang.reflect.Proxy#newProxyInstance,因为机器上用的是 JDK 1.8,代码与之前有点小区别,不过问题不大。

    @CallerSensitive// 这个注解不懂是啥,Google 一下,还是没懂,先看看文末的参考吧,有懂的同学,麻烦指点一二
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 生成代理类的地方,需要进去看一看
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // 创建代理对象
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            //...省略部分不看的内容
        }
    }

主要想看的是java.lang.reflect.Proxy#getProxyClass0是如何生成代理类的:

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

proxyClassCache 是一个静态变量,缓存了代理类:

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

这里需要注意一下创建缓存的构造方法的两个参数,两个参数的类都实现了BiFunction接口,Java8 的新特性:函数式接口。简单理解就是接口中定义了一个方法,接收两个参数,一顿操作之后,返回一个结果。先看缓存的构造方法:

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

记住subKeyFactoryvalueFactory这两个变量是啥,马上就会用到。

先看缓存的java.lang.reflect.WeakCache#get方法,方法比较长,不用全部看,关注几个注释的地方即可,具体细节可自行 Debug:

    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap 生成 key,subKeyFactory 就是前面提到的函数对象
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                // 上面的注释都写明白了,获取出来的对象的类都实现了 Supplier 接口
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {// 创建工厂
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {//  用 factory 替换 supplier
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

生成 key 就不看了,直接看V value = supplier.get();这行代码,初次调用时,肯定没有缓存,所以先看java.lang.reflect.WeakCache.Factory#get

        @Override
        public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {// 这个地方的 valueFactory 就是前面说到的 ProxyClassFactory 对象
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // put into reverseMap
            reverseMap.put(cacheValue, Boolean.TRUE);

            // try replacing us with CacheValue (this should always succeed)
            if (!valuesMap.replace(subKey, this, cacheValue)) {// 添加缓存
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }

接下来要看的是java.lang.reflect.Proxy.ProxyClassFactory#apply方法,主要这一行:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

这是 JDK 提供的生成代理类的工具,反编译出的代码如下:

未完待续,先睡觉....

参考:

猜你喜欢

转载自www.cnblogs.com/magexi/p/11762577.html
今日推荐