1. 程式人生 > >關於JDK動態代理的具體實現

關於JDK動態代理的具體實現

orm hat HA ati SM 理解 mov miss eth

  最近學習了關於jdk動態代理的相關內容,記錄如下:

  jdk動態代理中主要涉及到的相關類:

  1、jdk實現動態代理主要通過目標接口實現,被代理的目標類和生成的代理類必須實現相同的接口

   以下舉例:

 1 //共同實現的接口
 2 public interface Base {
 3     void say();
 4 }
 5 
 6 //目標類
 7 public class Subject implements Base {
 8 
 9     public void say(){
10         System.out.println("我是原始類,我說話了");
11     }
12 }

  2、InvocationHandler 接口:這個是java反射包中的一個接口。我將它理解為一個調度者的角色。這個接口只有一個方法。對於每個代理類都會有一個相關的Handler實現。

//方法有三個參數,分別是代理類實例,方法,以及方法的參數
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

當我們調用代理類的具體方法時,實際上調用的是Handler的這個方法,後面可以證明。

  3、ClassLoader對象,類加載器。當我們生成一個代理對象實例時,需要指定某一個類加載器來加載生成的代理類。

  4、Proxy類,通過這個類的 靜態方法 newProxyInstance 方法能夠生成代理類的實例。該方法需要三個參數,分別為:類加載器,接口集合,handler對象實例。其結果就是 通過制定的類加載器生成了一個實現了接口集合的代理類實例,調用該對象的方法需要調用handler的invoke方法。

一個簡單的動態代理的demo:

//實現自己的Handler
public class MyHandler implements InvocationHandler {

    //這裏保留了一個目標對象
    private Base base;

    public MyHandler(Base base){
        
this.base = base; } //重寫invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("handler 的invoke方法開始調用"); Object o = method.invoke(base,args); System.out.println("handler 的invoke方法調用完成"); return o; } } //測試類 public class Test { public static void main(String[] args) { // 目標對象 Subject subject = new Subject(); //自己定義的handler對象 MyHandler myHandler = new MyHandler(subject); //類加載器 ClassLoader classLoader = myHandler.getClass().getClassLoader(); //接口數組,目標對象所有實現的接口 Class[] interfaces = subject.getClass().getInterfaces(); Base proxy = (Base) Proxy.newProxyInstance(classLoader,interfaces,myHandler); proxy.say(); } }

 執行結果:

技術分享圖片

  那麽在整個過程重到底發生了什麽?

代理對象生成在於 :

 Base proxy = (Base) Proxy.newProxyInstance(classLoader,interfaces,myHandler);

點進去看看:

    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);  //關鍵一,拿到代理類的class類,參數分別為類加載器和接口數組

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
        //以代理類的class類 拿到構造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
        //獲取構造函數需要的參數,即是handler的實現。
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});//關鍵二,通過構造函數生成實例並返回,註意這裏的構造函數中需要一個handler數組對象。 } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }

從上面的代碼來看,關鍵一的部分生成了代理類的Class類。那麽這個方法裏面是什麽呢,點進去看看。

  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對象是Proxy類的一個成員變量,它的 類型為 WeakCache,從描述來看是一個專門用來緩存Proxy Class的元素。

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

對於我來說這個類是一個很難搞得類型,裏面所涉及到的東西有很多我都不太懂,只能看個大概。

大體上來說,這是具有二級緩存功能的類。

先看成員變量和構造函數。

//這個變量暫時不用理會,大體上是一個和垃圾回收有關的變量,我也不懂
private
final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
// the key type is Object for supporting null key

//這個map就是用來保存緩存內容的map集合了,前面的concurrent表明這是一個線程安全的map類型,具體實現不清楚,暫時理解為一個普通的map。
//其實從這個map的value的形式也能大致看出,這個value:ConcurrentMap<Object,Supplier<V>>就是二級緩存的部分了,同樣是一個map結構。 private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();

//這個BiFunction簡單理解為一個函數,它是一個接口,下面用到了再說。
private final BiFunction<K, P, ?> subKeyFactory; private final BiFunction<K, P, V> valueFactory; //構造函數,就是初始化了兩個成員變量 public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }

以上的內容先有個印象,重點在於它的get方法,看源碼。

//先看參數,對應上面的關鍵三,K是類加載器,P 是接口數組,這個方法的核心邏輯就是通過類加載器和接口類型數組獲取緩存中的代理類Class 對象。   
public V get(K key, P parameter) {
     Objects.requireNonNull(parameter); expungeStaleEntries();     // 簡單理解就是通過類加載器對象生成一個一級緩存,map中的key。 Object cacheKey
= CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey
    //然後根據生成的cacheKey,在map裏面找二級緩存的map,就是這裏的valueMap
    //通過這裏其實就看出來,對於不同的類加載器,所對應的代理類是不同的。一級緩存Map中的Key,其實就是類加載器。 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);

    //對於第一次取值的時候,valueMap肯定是空,需要完成初始化。這裏涉及到一點同步的設計,
if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap
      //putIfAbsent方法的核心邏輯是:如果cacheKey是map中的一個key,則返回這個key所對應的value;否則就執行map.put(cacheKey,valueMap=new ConcurrentHashMap<>())。
      //這個方法將對於第一次執行時顯然應該執行map.put(cacheKey,valueMap=new ConcurrentHashMap<>()),它會返回null。  
= map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>());
        //正常情況下,這裏的oldValue應該是位null,如果不為NULL,則表明在同時有另外的線程同時進行了這部分初始化的內容,為了保證一致性,執行下面的代碼。
if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap
    //這個我理解為生成二級緩存map中的key,可以看出,二級緩存的key是有類加載器和接口數組共同組成的。
    //subKeyFactory 是成員變量中的一個函數對象,這個函數的apply方法就是你給它參數,他根據參數返回一個對象,有點類似工廠模式,所以這個函數的命名也叫subKeyFactory,這個subKey就是二級緩存map中的key。 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

     //通過key,在二級緩存中找value 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實際上是factory,factory.get()是什麽? 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
        //這裏初始化了factory對象 if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); }
        //第一次循環先執行這裏,和上面同步的思路類似,第一次value(supplier)放的是一個factory。
if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else {
          //這裏是第二次請求get()方法時運行的代碼
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); } } } }


到目前為止,還是沒有搞清楚代理類的class是怎麽來的還需要看Factory類的get()方法。

    private final class Factory implements Supplier<V> {

        private final K key;
        private final P parameter;
        private final Object subKey;
        private final ConcurrentMap<Object, Supplier<V>> valuesMap;

        Factory(K key, P parameter, Object subKey,
                ConcurrentMap<Object, Supplier<V>> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

    //這裏就是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 {
          //這裏就是value的生成方法,前面的Objects.requireNonNull()近似的理解為確保不為空,還要繼續深入。 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; } }


繼續查看valueFactory,更具Proxy類中weakCeach屬性,可知valueFactory是一個ProxyClassFactory,終於要看到曙光了。

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
    //需要兩個參數,一個類加載器,一個接口數組。
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        //通過參數中的類加載器將所有的接口數組中的接口Class加載到虛擬機中 Map
<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */

        //對於不是public類型的接口,代理類將定義在相同的包中。驗證所有的非public接口在同一個包中,不在一個包中會拋異常。 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);
try {
          //這裏的defineClass0方法的實現是一個本地方法,不用管了,有字節數組就夠了。
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } }


既然 ProxyGenerator.generateProxyClass()方法能生成一個字節數組,那我們就來看看這這數組到底是什麽。

測試一下:

public class Test1 {
    public static void main(String[] args) {

        Subject sub = new Subject();

        Class[] interfaces = sub.getClass().getInterfaces();

       byte[] classFile =  ProxyGenerator.generateProxyClass("SubProxy",interfaces);

        FileOutputStream out = null;

        try {
            out = new FileOutputStream(new File("SubProxy.class"));
            out.write(classFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

得到文件 SubProxy.class

反編譯看看:

import com.caiyan.entitry.Base;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class SubProxy extends Proxy implements Base {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

//構造函數,對應了上面的關鍵二的部分。
public SubProxy(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 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); } } //每個代理方法都調用了handler的invoke方法 public final void say() throws { try { super.h.invoke(this, m3, (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")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.caiyan.entitry.Base").getMethod("say"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }


截止目前,基本理清了jdk動態代理的大體實現。

參考了其他的兩篇博客:

https://blog.csdn.net/bluetjs/article/details/52263410

https://www.jianshu.com/p/9f5566b5e7fb

感謝學習路上能遇到那些貢獻經驗的大神~

關於JDK動態代理的具體實現