番外篇,jdk自帶動態代理源碼分析

之前和同學聊起代理模式,順嘴提到了動態代理,就順便看了一下源碼,話不多說,開始分析,和之前一樣爲了方便理解,我會直接在代碼中註釋

這是一段很常見的動態代理代碼,TestInterface是一個接口,裏面只有一個test方法,TestInterfaceImpl類實現了TestInterface接口,代碼也比較簡單,我就不全部貼出來了

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

public class Test implements InvocationHandler {

    public  TestInterface ti;

    public Object newProxyInstance(TestInterface ti) {
        this.ti = ti;
        //重點
        return Proxy.newProxyInstance(ti.getClass().getClassLoader(), ti.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("執行方法前的操作");
        if(method.getName().equals("test"))
        {
            ti.test();
        }
        System.out.println("執行方法後的操作");
        return null;
    }

    public static void main(String[] args) {
        Test test =new Test ();
        TestInterface ti = (TestInterface)test.newProxyInstance(new TestInterfaceImpl());
        ti.test();
    }
}

重點是Proxy.newProxyInstance方法

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
        //若傳入的動態代理類爲空拋出異常
        Objects.requireNonNull(h);
		//獲取當前系統的安全檢查器
		//因爲這裏會進行類加載和io操作,需要進行安全檢查
        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
         //關鍵方法
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
		//此處只是調用Constructor的newInstance方法
		//把動態代理對象傳入,調用對應的構造方法
		//返回一個動態代理後的實體類
		//意義不大,這裏就不多介紹
        return newProxyInstance(caller, cons, h);
    }

進入關鍵方法getProxyConstructor

private static Constructor<?> getProxyConstructor(Class<?> caller,
                                                      ClassLoader loader,
                                                      Class<?>... interfaces)
    {
        //判斷需要代理的接口是否爲多個,進行簡單轉換
        //if else內容幾乎一致,就只對前面的if內容進行分析,不再贅述
        if (interfaces.length == 1) {
            Class<?> intf = interfaces[0];
            //判斷是否需要進行安全檢查
            if (caller != null) {
                checkProxyAccess(caller, loader, intf);
            }
            //重點方法,我會進行單獨講解
            return proxyCache.sub(intf).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
        } else {
            // interfaces cloned
            final Class<?>[] intfsArray = interfaces.clone();
            if (caller != null) {
                checkProxyAccess(caller, loader, intfsArray);
            }
            final List<Class<?>> intfs = Arrays.asList(intfsArray);
            return proxyCache.sub(intfs).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
        }
    }

這段代碼相當優雅,把lanbda表達式寫的出神入化(但是我不建議大家平時這樣寫,可讀性極差,我自己看這段代碼蒙了有一會)

return proxyCache.sub(intf).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );

首先我們來看computeIfAbsent方法

public V computeIfAbsent(ClassLoader cl,
                             BiFunction<
                                 ? super ClassLoader,
                                 ? super CLV,
                                 ? extends V
                                 > mappingFunction)

lanbda表達式推導的就是BiFunction接口的方法,進入BiFunction接口

public interface BiFunction<T, U, R> {
    R apply(T t, U u);
    。。。省略。。。
}

問題來了,我們可以把lanbda表達式寫成下面的代碼

R apply(T ld, U clv){
	return new ProxyBuilder(ld, clv.key()).build();
}

然後通過類型推導(根據computeIfAbsent方法進行推導)將代碼推導爲

R apply(ClassLoader ld, U clv){
	return new ProxyBuilder(ld, clv.key()).build();
}

再根據sub方法,和AbstractClassLoaderValue,Sub類進行進一步的推導

public abstract class AbstractClassLoaderValue<CLV extends AbstractClassLoaderValue<CLV, V>, V>
public final class Sub<K> extends AbstractClassLoaderValue<Sub<K>, V>
public <K> Sub<K> sub(K key) {
        return new Sub<K>(key);
    }

最終才能得到推導後的方法

R apply(ClassLoader ld, Sub clv){
	return new ProxyBuilder(ld, clv.key()).build();
}

但是,此時返回值依然是不確定的,根據build的返回值推導,爲Constructor,最終的方法才能得到

Constructor apply(ClassLoader ld, Sub clv){
	return new ProxyBuilder(ld, clv.key()).build();
}

確實挺優雅的,就是太難理解,進入computeIfAbsent方法進行分析,設計的有點繞,猜測是爲了解決複用性

public V computeIfAbsent(ClassLoader cl,
                             BiFunction<
                                 ? super ClassLoader,
                                 ? super CLV,
                                 ? extends V
                                 > mappingFunction) throws IllegalStateException {
        //創建map集合,注意,此處會根據類加載器加載對應的map集合
        ConcurrentHashMap<CLV, Object> map = map(cl);
        @SuppressWarnings("unchecked")
        //獲取自身對象此處爲sub對象
        CLV clv = (CLV) this;
        Memoizer<CLV, V> mv = null;
        while (true) {
        	//查看mv對象是否爲空,如果爲空(即,首次進入循環),嘗試從集合中獲取vsl
        	//如果可以獲取,認爲該類已經加載,直接返回類對象
        	//否則進行添加並賦值給val
            Object val = (mv == null) ? map.get(clv) : map.putIfAbsent(clv, mv);
            //當第一次運行時,val和mv均爲null
            if (val == null) {
                if (mv == null) {
                    // create Memoizer lazily when 1st needed and restart loop
                    //創建Memoizer對象
                    //只做一件事,將三個參數賦值給自身的成員變量
                    mv = new Memoizer<>(cl, clv, mappingFunction);
                    continue;
                }
                // mv != null, therefore sv == null was a result of successful
                // putIfAbsent
                try {
                    // trigger Memoizer to compute the value
                    //主要方法
                    V v = mv.get();
                    // attempt to replace our Memoizer with the value
                    //替換元素
                    map.replace(clv, mv, v);
                    // return computed value
                    return v;
                } catch (Throwable t) {
                    // our Memoizer has thrown, attempt to remove it
                    map.remove(clv, mv);
                    // propagate exception because it's from our Memoizer
                    throw t;
                }
            } else {
                try {
                	//如果進行到這一步,說明map集合中存在已經加載好的類
                	//判斷是否爲Memoizer(若爲Memoizer可能是多線程條件下get方法尚未完成)
                	//然後返回對應的類,或是繼續調用get方法
                    return extractValue(val);
                } catch (Memoizer.RecursiveInvocationException e) {
                    // propagate recursive attempts to calculate the same
                    // value as being calculated at the moment
                    throw e;
                } catch (Throwable t) {
                    // don't propagate exceptions thrown from foreign Memoizer -
                    // pretend that there was no entry and retry
                    // (foreign computeIfAbsent invocation will try to remove it anyway)
                }
            }
            // TODO:
            // Thread.onSpinLoop(); // when available
        }
    }

get方法

public V get() throws RecursiveInvocationException {
            V v = this.v;
            if (v != null) return v;
            Throwable t = this.t;
            if (t == null) {
                synchronized (this) {
                    if ((v = this.v) == null && (t = this.t) == null) {
                        if (inCall) {
                            throw new RecursiveInvocationException();
                        }
                        inCall = true;
                        try {
                            this.v = v = Objects.requireNonNull(
                            	//前面後面都是健壯性和複用性檢測
                            	//沒什麼好看的關鍵是是這裏
                            	//調用前面用lanbda表達式傳入發方法
                                mappingFunction.apply(cl, clv));
                        } catch (Throwable x) {
                            this.t = t = x;
                        } finally {
                            inCall = false;
                        }
                    }
                }
            }
            if (v != null) return v;
            if (t instanceof Error) {
                throw (Error) t;
            } else if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new UndeclaredThrowableException(t);
            }
        }

回到之前的build方法

Constructor<?> build() {
			//核心,返回class對象
            Class<?> proxyClass = defineProxyClass(module, interfaces);
            final Constructor<?> cons;
            try {
            	//返回對應的構造方法,沒什麼好看的
                cons = proxyClass.getConstructor(constructorParams);
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
            return cons;
        }

defineProxyClass方法

private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
            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.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;  // non-public, final
                    String pkg = intf.getPackageName();
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // all proxy interfaces are public
                proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
                                       : PROXY_PACKAGE_PREFIX;
            } else if (proxyPkg.isEmpty() && m.isNamed()) {
                throw new IllegalArgumentException(
                        "Unnamed package cannot be added to " + m);
            }

            if (m.isNamed()) {
                if (!m.getDescriptor().packages().contains(proxyPkg)) {
                    throw new InternalError(proxyPkg + " not exist in " + m.getName());
                }
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg.isEmpty()
                                    ? proxyClassNamePrefix + num
                                    : proxyPkg + "." + proxyClassNamePrefix + num;

            ClassLoader loader = getLoader(m);
            trace(proxyName, m, loader, interfaces);

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
            try {
                Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
                                                 0, proxyClassFile.length,
                                                 loader, null);
                reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
                return pc;
            } 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());
            }
        }

其他都是做一些檢驗,沒什麼好說的,其實這麼一大段重要的就下面

//生成動態代理字節碼
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
            try {
            	//通過類加載器加載字節碼
                Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
                                                 0, proxyClassFile.length,
                                                 loader, null);
                reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
                return pc;

最終生成字節碼也就是在內存中生成.class文件的方法,大家看看就行了,太多了,而且也沒啥技術含量,方法和需要實現的接口方法內部字節碼都是基本固定的,無非是把實現的接口方法轉發到一個統一的方法中,再通過統一方法調用我們自己實現的invoke方法,就是實現的接口,導包的路徑,類名稱不同,稍有jvm常識就能自己寫一個,就是費時間而已

private byte[] generateClassFile() {

        /* ============================================================
         * Step 1: Assemble ProxyMethod objects for all methods to
         * generate proxy dispatching code for.
         */

        /*
         * Record that proxy methods are needed for the hashCode, equals,
         * and toString methods of java.lang.Object.  This is done before
         * the methods from the proxy interfaces so that the methods from
         * java.lang.Object take precedence over duplicate methods in the
         * proxy interfaces.
         */
        //添加hashCode,equals,toString方法
        addProxyMethod(hashCodeMethod, Object.class);
        addProxyMethod(equalsMethod, Object.class);
        addProxyMethod(toStringMethod, Object.class);

        /*
         * Now record all of the methods from the proxy interfaces, giving
         * earlier interfaces precedence over later ones with duplicate
         * methods.
         */
        for (Class<?> intf : interfaces) {
            for (Method m : intf.getMethods()) {
                addProxyMethod(m, intf);
            }
        }

        /*
         * For each set of proxy methods with the same signature,
         * verify that the methods' return types are compatible.
         */
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            checkReturnTypes(sigmethods);
        }

        /* ============================================================
         * Step 2: Assemble FieldInfo and MethodInfo structs for all of
         * fields and methods in the class we are generating.
         */
        try {
            methods.add(generateConstructor());
			//開始生成代理方法
            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
                for (ProxyMethod pm : sigmethods) {

                    // add static field for method's Method object
                    //生成對應的方法訪問標誌
                    fields.add(new FieldInfo(pm.methodFieldName,
                        "Ljava/lang/reflect/Method;",
                         ACC_PRIVATE | ACC_STATIC));

                    // generate code for proxy method and add it
                    //生成代理方法
                    methods.add(pm.generateMethod());
                }
            }
			//添加靜態塊
            methods.add(generateStaticInitializer());

        } catch (IOException e) {
            throw new InternalError("unexpected I/O Exception", e);
        }
		
        if (methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        }
        if (fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        }

        /* ============================================================
         * Step 3: Write the final class file.
         */

        /*
         * Make sure that constant pool indexes are reserved for the
         * following items before starting to write the final class file.
         */
        //獲取類名(稍後還要進行拼接)和父類名
        cp.getClass(dotToSlash(className));
        cp.getClass(superclassName);
        //獲取所有接口名
        for (Class<?> intf: interfaces) {
            cp.getClass(dotToSlash(intf.getName()));
        }

        /*
         * Disallow new constant pool additions beyond this point, since
         * we are about to write the final constant pool table.
         */
        cp.setReadOnly();

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        try {
            /*
             * Write all the items of the "ClassFile" structure.
             * See JVMS section 4.1.
             */
                                        // u4 magic;
			//添加魔數
            dout.writeInt(0xCAFEBABE);
                                        // u2 minor_version;
          	//添加版本信息
            dout.writeShort(CLASSFILE_MINOR_VERSION);
                                        // u2 major_version;
       		//添加小版本信息
            dout.writeShort(CLASSFILE_MAJOR_VERSION);
			//添加常量池
            cp.write(dout);             // (write constant pool)

                                        // u2 access_flags;
            //添加標誌位
            dout.writeShort(accessFlags);
                                        // u2 this_class;
            //添加類名
            dout.writeShort(cp.getClass(dotToSlash(className)));
                                        // u2 super_class;
            //添加父類名
            dout.writeShort(cp.getClass(superclassName));

                                        // u2 interfaces_count;
            //添加接口表標誌位
            dout.writeShort(interfaces.length);
                                        // u2 interfaces[interfaces_count];
            //添加接口
            for (Class<?> intf : interfaces) {
                dout.writeShort(cp.getClass(
                    dotToSlash(intf.getName())));
            }

                                        // u2 fields_count;
            //添加字段表標誌位
            dout.writeShort(fields.size());
                                        // field_info fields[fields_count];
          	//添加字段
            for (FieldInfo f : fields) {
                f.write(dout);
            }

                                        // u2 methods_count;
            //添加方法表標誌位
            dout.writeShort(methods.size());
                                        // method_info methods[methods_count];
            //添加方法
            for (MethodInfo m : methods) {
                m.write(dout);
            }

                                         // u2 attributes_count;
            //類文件屬性,稍後會在另外一個方法設置
            dout.writeShort(0); // (no ClassFile attributes for proxy classes)

        } catch (IOException e) {
            throw new InternalError("unexpected I/O Exception", e);
        }

        return bout.toByteArray();
    }

通過反射獲取生成的class字節碼

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class Test {
    private static void saveProxyFile() {
        FileOutputStream out = null;
        try {
            Class clazz = Class.forName("java.lang.reflect.ProxyGenerator");
            Method m = clazz.getDeclaredMethod("generateProxyClass", String.class, Class[].class);
            m.setAccessible(true);
            byte[] bs = (byte[]) m.invoke(null, "$Proxy0", new Class[]{TestInterface.class});
            out = new FileOutputStream("$Proxy0.class");
            out.write(bs);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        saveProxyFile();
    }
}

生成的class字節碼

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

public final class $Proxy0 extends Proxy implements TestInterface {
	//方法對象
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
	//使用父類的構造方法處理
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
	//將所有方法轉發到父類h屬性的invoke方法
    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 test() 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("TestInterface").getMethod("test");
            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());
        }
    }
}

父類的構造方法,最終所有方法都指向我們傳入的類的invoke方法

protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

獲取class對象的方法,因爲是native 修飾,我就不繼續下去了

public native Class<?> defineClass0(String name, byte[] b, int off, int len,
                                        ClassLoader loader,
                                        ProtectionDomain protectionDomain);

至此,分析結束

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