JDK8動態代理實現與原理解析

第一部分:JDK8動態代理基本實現

1,先定義一個接口
public interface UserService {
    void work(String workContent);
}
2,再定義一個接口實現類
public class StudentService implements UserService {
    @Override
    public void work(String workContent) {
        System.out.println("StudentService work:" + workContent);
    }
}
3,定義最關鍵的InvocationHandler實現類
public class UserProxyHandler implements InvocationHandler {
    UserService realService;
    UserService proxyInstance;

    public UserProxyHandler(UserService userService) {
        realService = userService;
        //關鍵點1:代理實例生成
        proxyInstance = (UserService) Proxy.newProxyInstance(getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
    }

    public UserService getRealService() {
        return realService;
    }

    public UserService getProxyInstance() {
        return proxyInstance;
    }

     // 關鍵點2:代理實例的接口方法會調用InvocationHandler的invoke方法
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("UserProxyHandler before");
        // 代理實現的地方
        Object result = method.invoke(realService, objects);
        System.out.println("UserProxyHandler after");
        return result;
    }
}
4,調用代理類,觀察代理過程
StudentService studentService = new StudentService();
UserProxyHandler userProxyHandler = new UserProxyHandler(studentService);
userProxyHandler.getProxyInstance().work("proxy go school");

輸出結果:
在這裏插入圖片描述

結果分析

整個過程結果都看到,我們明明調用的是代理對象的work方法,但最終還是進入了UserProxyHandler的invoke方法,並通過代理層,調用了真實類的StudentService的work方法。

但是我們還是不清楚JDK到底是如何實現這一步的,其實重點就是2個問題:

  1. 代理對象是如何產生的
  2. InvocationHandler的invoke方法具體的怎麼調用的

那就老老實實看源碼

第二部分:JDK8動態代理原理解析

一,代理對象的產生過程

這部分基本就要看JDK8的源碼了,直接IDEA上面一步步,看源碼的實現過程,這裏只分析重點代碼。

Proxy.newProxyInstance方法

將該方法簡化後,其實就做了三部:

  1. 得到代理類的Class對象
  2. 獲得該Class對象的構造函數反射
  3. 調用構造函數反射生成對象
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,,InvocationHandler h) {
    Class<?> cl = getProxyClass0(loader, intfs);
    final Constructor<?> cons = cl.getConstructor(constructorParams);
	return cons.newInstance(new Object[]{h});
}

很明顯,其中重要的就是第一步,jdk如何得到代理類的Class對象,
該Class對象的生成過程getProxyClass0()。

getProxyClass0()

然而,這個方法內部很簡單。

private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        return proxyClassCache.get(loader, interfaces);
    }
proxyClassCache.get()
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

該方法主要是做了一層內存緩存。具體的Class生成過程其實在ProxyClassFactory裏面

緩存過程分析:

get方法首先創建一個valuesMap,獲取subKey,裏面比較重要的就是subKeyFactory.apply(key,parameter),這個方法會幫我們生成代理類的subKey,之後會建立一個Factory,當使用Factory.get的時候,回去調用valueFactory.apply()
valueFactory即構造函數裏面的ProxyClassFactory,便是真正生成代理類的時候。

緩存的思考:

由於第一次的時候需要動態的去創建字節碼,然後進行加載,初始化,因此效率和直接new對象相比會比較低下。 這也是使用緩存的原因。雖然有緩存,但是由於使用了WeakReference,GC後有可能會被回收,那麼就得重新加載,一定程度上會降低效率,所以一般情況下,我們儘量避免這種動態生成類的方式,而是用在編譯時生成類的方式取代,這便是APT技術的精髓。

public V get(K key, P parameter) {
        Object cacheKey = CacheKey.valueOf(key, refQueue);
        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
        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
                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 {
                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);
                }
            }
        }
    }
ProxyClassFactory.apply()

這裏面主要五點,
1,利用Class.forName複製一份接口參數傳入的接口Class對象
2,拼接Proxy的類名形爲: xxx$Proxy0
3,代理類的accessFlags
4,ProxyGenerator.generateProxyClass()獲得Class字節碼
5,ProxyGenerator.defineClass0() 通過native調用加載字節碼,獲取Java層Proxy的Class對象

@Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                Class<?> interfaceClass = null;
                interfaceClass = Class.forName(intf.getName(), false, loader);
            }
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }
            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
        }

至此,代理類的對象生成過程就徹底搞清楚了

二,InvocationHandler的invoke調用時機

我們大膽猜測,具體過程肯定都在ProxyGenerator.generateProxyClass()的生成過程中。
也就是裏面的generateClassFile()方法中,此處代碼沒有註釋,只能猜測着看
直接搜索InvocationHandler,很明顯發現:
1, generateConstructor 生成了注入InvocationHandler的代理類構造函數

private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
        ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
        DataOutputStream var2 = new DataOutputStream(var1.code);
        this.code_aload(0, var2);
        this.code_aload(1, var2);
        var2.writeByte(183);
        var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
        var2.writeByte(177);
        var1.maxStack = 10;
        var1.maxLocals = 2;
        var1.declaredExceptions = new short[0];
        return var1;
    }

2,ProxyMethod.generateMethod 生成了調用InvocationHandler.invoke的代理接口方法(這裏只展示部分代碼)

private ProxyGenerator.MethodInfo generateMethod() throws IOException {
        String var1 = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);
        ProxyGenerator.MethodInfo var2 = ProxyGenerator.this.new MethodInfo(this.methodName, var1, 17);
        int[] var3 = new int[this.parameterTypes.length];
        int var4 = 1;
        for(int var5 = 0; var5 < var3.length; ++var5) {
            var3[var5] = var4;
            var4 += ProxyGenerator.getWordsPerType(this.parameterTypes[var5]);
        }
        byte var7 = 0;
        DataOutputStream var9 = new DataOutputStream(var2.code);
        ProxyGenerator.this.code_aload(0, var9);
        var9.writeByte(180);
	    var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
        ProxyGenerator.this.code_aload(0, var9);
        var9.writeByte(178);
        var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));
        if (this.parameterTypes.length > 0) {
            ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);
            var9.writeByte(189);
            var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));

            for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {
                var9.writeByte(89);
                ProxyGenerator.this.code_ipush(var10, var9);
                this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);
                var9.writeByte(83);
            }
        } else {
            var9.writeByte(1);
        }
        var9.writeByte(185);
        var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"));
        var9.writeByte(4);
        var9.writeByte(0);
}

我們可以調用ProxyGenerator.generateProxyClass來看一下這個生成的類,把它寫到文件裏,然後打開驗證一下,關鍵方法如下所示:

public final void work(String var1) throws  {
        try {
             super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
}

至此,謎底全部解開了!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章