原文鏈接: JDK動(dòng)態(tài)代理實(shí)現(xiàn)機(jī)制   轉(zhuǎn)載請(qǐng)注明出處!

===========================================

本文只對(duì)JDK動(dòng)態(tài)代理的底層實(shí)現(xiàn)進(jìn)行分析,如需了解代理模式和動(dòng)態(tài)代理的使用請(qǐng)移步:設(shè)計(jì)模式—代理模式     動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式(JDK/Cglib)

在讀代碼之前先清楚兩個(gè)概念:

  1、Class類存儲(chǔ)的是類的所有信息,包括類的所有方法、屬性、實(shí)現(xiàn)接口等。每個(gè)類對(duì)應(yīng)一個(gè)Class對(duì)象(單例),Class對(duì)象是由classLoader加載出來的,使用雙親委派模型來保證class只會(huì)被加載一次。

  2、classLoader在加載類的時(shí)候不管class文件是從哪里來的,無論是從.class文件、網(wǎng)絡(luò)、數(shù)據(jù)庫(kù)類加載器都不關(guān)心。他只關(guān)心給他的class二進(jìn)制流是不是能夠通過校驗(yàn)。

說明:以下測(cè)試代碼和 動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式(JDK/Cglib)相同

使用JDK動(dòng)態(tài)代理需要實(shí)現(xiàn)InvocationHandler接口,同時(shí)實(shí)現(xiàn)invoke()方法。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

package com.zpj.proxy.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/**
 * Created by Perkins on 2017/4/2. */public class JDKProxy implements InvocationHandler {    private Object person;    public Object getInstance(Object person) {        this.person = person;        return Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
    }

    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("doSomething---------start");
        method.invoke(person, args);
        System.out.println("doSomething---------end");        return null;
    }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

測(cè)試代碼如下:

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

package com.zpj.proxy.jdk;/**
 * Created by Perkins on 2017/4/2. */public class Run {    public static void main(String[] args) {
        Person person = (Person) new JDKProxy().getInstance(new MrLi());
        person.doWork();
    }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

 

運(yùn)行的時(shí)候在person處打斷點(diǎn)可看到person的類名為$Proxy0而不是Person或者M(jìn)rLi,則說明該返回對(duì)象是Person的實(shí)現(xiàn)類。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

我們添加如下代碼把person的class中的方法打印出來

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

package com.zpj.proxy.jdk;/**
 * Created by Perkins on 2017/4/2. */import java.lang.reflect.Method;public class Run {    private Method method;    public static void main(String[] args) {
       Person person = (Person) new JDKProxy().getInstance(new MrLi());
       Method [] methods = person.getClass().getMethods();       for(int i =0; i<methods.length;i++){
           System.out.println(methods[i].getName());
       }
        person.doWork();
    }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

 

結(jié)果如下,很明顯紅框中的方法不屬于Person也不屬于Object中的方法。這更進(jìn)一步說明返回的person并不是Person的實(shí)例。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

下面就進(jìn)入底層代碼對(duì)JDK動(dòng)態(tài)代理進(jìn)行解析。

這里直接對(duì)Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);進(jìn)行分析。

 

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException{        if (h == null) {        //驗(yàn)證InvocationHandler不允許為null
        throw new NullPointerException();
        }    /*
     * Look up or generate the designated proxy class.     */
    //調(diào)用getProxyClass()獲取Class實(shí)例,該實(shí)例便是返回的代理Person的實(shí)例,此方法為重點(diǎn)?。?!
        Class cl = getProxyClass(loader, interfaces);    /*
     * Invoke its constructor with the designated invocation handler.     */
        try {        //利用反射機(jī)制從Class中取出構(gòu)造器創(chuàng)建對(duì)象
        Constructor cons = cl.getConstructor(constructorParams);        return (Object) cons.newInstance(new Object[] { h });
        } catch (NoSuchMethodException e) {        throw new InternalError(e.toString());
        } catch (IllegalAccessException e) {        throw new InternalError(e.toString());
        } catch (InstantiationException e) {        throw new InternalError(e.toString());
        } catch (InvocationTargetException e) {        throw new InternalError(e.toString());
        }
        }

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

 

 在上面方法中調(diào)用public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)throws IllegalArgumentException獲取了Class實(shí)例,下面進(jìn)入該方法進(jìn)行分析。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException {        if (interfaces.length > 65535) {            //驗(yàn)證接口數(shù)量不允許超過65535
            throw new IllegalArgumentException("interface limit exceeded");
        }        //************開始對(duì)interface進(jìn)行循環(huán)驗(yàn)證,驗(yàn)證通過則加入interfaceNames中***************************
        Class proxyClass = null;    /* collect interface names to use as key for proxy class cache */
        String[] interfaceNames = new String[interfaces.length];
        Set interfaceSet = new HashSet();    // for detecting duplicates
        for (int i = 0; i < interfaces.length; i++) {//循環(huán)對(duì)所有接口進(jìn)行操作
        /*
         * Verify that the class loader resolves the name of this
         * interface to the same Class object.         */
            String interfaceName = interfaces[i].getName();
            Class interfaceClass = null;            try {                //根據(jù)名稱獲取接口的Class
                interfaceClass = Class.forName(interfaceName, false, loader);
            } catch (ClassNotFoundException e) {
            }            if (interfaceClass != interfaces[i]) {                throw new IllegalArgumentException(interfaces[i] + " 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.contains(interfaceClass)) {                throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName());
            }
            interfaceSet.add(interfaceClass);
            interfaceNames[i] = interfaceName;
        }//************結(jié)束對(duì)interface進(jìn)行循環(huán)驗(yàn)證,存儲(chǔ)于interfaceNames中***************************
    /*
     * Using string representations of the proxy interfaces as
     * keys in the proxy class cache (instead of their Class
     * objects) is sufficient because we require the proxy
     * interfaces to be resolvable by name through the supplied
     * class loader, and it has the advantage that using a string
     * representation of a class makes for an implicit weak
     * reference to the class.     */
        Object key = Arrays.asList(interfaceNames);    /*
     * Find or create the proxy class cache for the class loader.     */
        Map cache;        synchronized (loaderToCache) {
            cache = (Map) loaderToCache.get(loader);            if (cache == null) {
                cache = new HashMap();
                loaderToCache.put(loader, cache);
            }        /*
         * This mapping will remain valid for the duration of this
         * method, without further synchronization, because the mapping
         * will only be removed if the class loader becomes unreachable.         */
        }    /*
     * Look up the list of interfaces in the proxy class cache using
     * the key.  This lookup will result in one of three possible
     * kinds of values:
     *     null, if there is currently no proxy class for the list of
     *         interfaces in the class loader,
     *     the pendingGenerationMarker object, if a proxy class for the
     *         list of interfaces is currently being generated,
     *     or a weak reference to a Class object, if a proxy class for
     *         the list of interfaces has already been generated.     */
        synchronized (cache) {        /*
         * Note that we need not worry about reaping the cache for
         * entries with cleared weak references because if a proxy class
         * has been garbage collected, its class loader will have been
         * garbage collected as well, so the entire cache will be reaped
         * from the loaderToCache map.         */
            do {
                Object value = cache.get(key);                if (value instanceof Reference) {
                    proxyClass = (Class) ((Reference) value).get();
                }                if (proxyClass != null) {                    // proxy class already generated: return it
                    return proxyClass;
                } else if (value == pendingGenerationMarker) {                    // proxy class being generated: wait for it
                    try {
                        cache.wait();
                    } catch (InterruptedException e) {            /*
             * The class generation that we are waiting for should
             * take a small, bounded time, so we can safely ignore
             * thread interrupts here.             */
                    }                    continue;
                } else {            /*
             * No proxy class for this list of interfaces has been
             * generated or is being generated, so we will go and
             * generate it now.  Mark it as pending generation.             */
                    cache.put(key, pendingGenerationMarker);                    break;
                }
            } while (true);
        }        try {
            String proxyPkg = null;    // package to define proxy class in
        /*
         * 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.         */
        //尋找到package的包路徑,為構(gòu)建代理類做準(zhǔn)備。同時(shí)要保證所有的非public代理接口在相同的包中
            for (int i = 0; i < interfaces.length; i++) {                int flags = interfaces[i].getModifiers();                if (!Modifier.isPublic(flags)) {
                    String name = interfaces[i].getName();                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));                    if (proxyPkg == null) {
                        proxyPk

http://www.cnblogs.com/PerkinsZhu/p/6658066.html