JAVA代理原始碼詳解,手動擼一個屬於自己的代理

語言: CN / TW / HK

一:常用的java代理模式

        一般經常做java開發的知道java的代理模式一共有三種,第一種也就是靜態代理,這種用法比較簡單,沒有什麼魔法棒,比較好理解,另外兩種分別是JDK代理和cglib代理,他們分別是對介面代理和對class類本身進行代理,jdk代理要求類必須實現有一個或者多個介面,對介面進行位元組碼增強在記憶體中實現新的class類去反射呼叫使用者target的實現類,這裡需要說明的是不管是cglic代理也好還是jdk代理他們在記憶體中都要佔據方法區資源(jdk8 叫原空間),從而達到代理目的,而cglib代理是對class類本身進行位元組碼增強配合fastclass來實現代理,關於更多的cglib和jdk代理相關的內容大家可以google搜尋一下,網上有很多這裡不做再多的說明。下面我們摒棄jdk,和cglib的複雜原始碼來自己實現一個代理模式,來更深刻的瞭解一下代理究竟是怎麼形成的。

二:JDK代理原始碼分析

       代理模式是指給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用。通俗的來講代理模式就是我們生活中常見的中介。這種模式有什麼用呢?它可以在原物件的基礎上增強原物件的功能,比如在原物件呼叫一個方法的前後進行日誌、事務操作等。Spring AOP就使用了代理模式。如何實現代理模式呢?首先來看靜態代理。靜態代理是指在程式執行前就已經存在的編譯好的代理類是為靜態代理。實現靜態代理有四個步驟:
     ①定義業務介面;
     ②被代理類實現業務介面;
     ③定義代理類並實現業務介面;
     ④最後便可通過客戶端進行呼叫。(這裡可以理解成程式的main方法裡的內容)
     我們按照這個步驟去實現靜態代理。需求:在向資料庫新增一個使用者時前後列印日誌。
 
JDK DEMO示例
 
IUserService.java
public interface IUserService {
    void add(String name);  
}

 

UserServiceImpl.java 

public class UserServiceImpl implements IUserService{

    @Override
    public void add(String name) {
        System.out.println("資料庫中插入:  "+name+" 的使用者");
    }

}

MyInvocationHandler.java

public class MyInvocationHandler implements InvocationHandler {
    //被代理物件,Object型別
    private Object target;
    
    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("準備向資料庫中插入資料");
        Object returnvalue = method.invoke(target, args);
        System.out.println("插入資料庫成功");

        return returnvalue;
    }
}

  

測試類

public static void main(String[] args) {

        IUserService target = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(target);
        IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
                target.getClass().getInterfaces(), handler);
        proxyObject.add("張玉龍");
    }

  使用上非常簡單、網上demo也很多,不做充分講解,對jdk代理用法的小夥伴如果還不熟悉這塊程式碼,就先了解一下jdk代理的使用方式,然後在回來繼續看下面的原始碼分析


JDK代理原始碼深度分析
 
這部分如果想要更快更好的理解,建議一邊對著原始碼(本文JDK 1.8),一邊看著部落格。畢竟自己親身實踐效果才好嘛。 Proxy.newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h) 產生了代理物件,所以我們進到 newProxyInstance 的實現:
 
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) {
        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);
    }
}

  

 
 
這段程式碼核心就是通過 getProxyClass0(loader, intfs)得到代理類的Class物件,然後通過Class物件得到構造方法,進而建立代理物件。下一步看 getProxyClass0這個方法。

//此方法也是Proxy類下的方法
    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
        //意思是:如果代理類被指定的類載入器loader定義了,並實現了給定的介面interfaces,
        //那麼就返回快取的代理類物件,否則使用ProxyClassFactory建立代理類。
        return proxyClassCache.get(loader, interfaces);
    }

 這裡看到proxyClassCache,有Cache便知道是快取的意思,正好呼應了前面Look up or generate the designated proxy class。查詢(在快取中已經有)或生成指定的代理類的class物件這段註釋。

proxyClassCache是個WeakCache類的物件,呼叫proxyClassCache.get(loader, interfaces); 可以得到快取的代理類或建立代理類(沒有快取的情況)。說明WeakCache中有 get這個方法。先看下WeakCache類的定義(這裡先只給出變數的定義和建構函式):

 
//K代表key的型別,P代表引數的型別,V代表value的型別。
// WeakCache<ClassLoader, Class<?>[], Class<?>>  proxyClassCache  說明proxyClassCache存的值是Class<?>物件,正是我們需要的代理類物件。
final class WeakCache<K, P, V> {

    private final ReferenceQueue<K> refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    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);
    }

  

 其中map變數是實現快取的核心變數,他是一個雙重的Map結構: (key, sub-key) -> value。其中key是傳進來的Classloader進行包裝後的物件,sub-key是由WeakCache建構函式傳人的 KeyFactory()生成的。value就是產生代理類的物件,是由WeakCache建構函式傳人的 ProxyClassFactory()生成的

 好,大體上說完WeakCache這個類的作用,我們回到剛才 proxyClassCache.get(loader, interfaces);這句程式碼。get是WeakCache裡的方法。原始碼如下
//K和P就是WeakCache定義中的泛型,key是類載入器,parameter是介面類陣列
public V get(K key, P parameter) {
        //檢查parameter不為空
        Objects.requireNonNull(parameter);
         //清除無效的快取
        expungeStaleEntries();
        // cacheKey就是(key, sub-key) -> value裡的一級key,
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //根據一級key得到 ConcurrentMap<Object, Supplier<V>>物件。如果之前不存在,則新建一個ConcurrentMap<Object, Supplier<V>>和cacheKey(一級key)一起放到map中。
        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
        //這部分就是呼叫生成sub-key的程式碼,上面我們已經看過怎麼生成的了
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //通過sub-key得到supplier
        Supplier<V> supplier = valuesMap.get(subKey);
        //supplier實際上就是這個factory
        Factory factory = null;

        while (true) {
            //如果快取裡有supplier ,那就直接通過get方法,得到代理類物件,返回,就結束了,一會兒分析get方法。
            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
            //下面的所有程式碼目的就是:如果快取中沒有supplier,則建立一個Factory物件,把factory物件在多執行緒的環境下安全的賦給supplier。
            //因為是在while(true)中,賦值成功後又回到上面去調get方法,返回才結束。
            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);
                }
            }
        }
    }

  所以接下來我們看Factory類中的get方法。

public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            //重新檢查得到的supplier是不是當前物件
            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生成的
                 //valueFactory就是我們傳入的 new ProxyClassFactory()
                //一會我們分析ProxyClassFactory()的apply方法
                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)
            //把value包裝成弱引用
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // put into reverseMap
            // 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;
        }
    }

  撥雲見日,來到ProxyClassFactory的apply方法,代理類就是在這裡生成的。

//這裡的BiFunction<T, U, R>是個函式式介面,可以理解為用T,U兩種型別做引數,得到R型別的返回值
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) {
              
            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
            //代理類訪問控制符: public ,final
            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.
             */
            //驗證所有非公共的介面在同一個包內;公共的就無需處理
            //生成包名和類名的邏輯,包名預設是com.sun.proxy,類名預設是$Proxy 加上一個自增的整數值
            //如果被代理類是 non-public proxy interface ,則用和被代理類介面一樣的包名
            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();
            //代理類的完全限定名,如com.sun.proxy.$Proxy0.calss
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            //核心部分,生成代理類的位元組碼
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //把代理類載入到JVM中,至此動態代理過程基本結束了
                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());
            }
        }
    }

  到這裡其實已經分析完了,但是本著深究的態度,決定看看JDK生成的動態代理位元組碼是什麼,於是我們將位元組碼儲存到磁碟上的class檔案中。程式碼如下:

public static void main(String[] args) {

        IUserService target = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(target);
        //第一個引數是指定代理類的類載入器(我們傳入當前測試類的類載入器)
        //第二個引數是代理類需要實現的介面(我們傳入被代理類實現的介面,這樣生成的代理類和被代理類就實現了相同的介面)
        //第三個引數是invocation handler,用來處理方法的呼叫。這裡傳入我們自己實現的handler
        IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
                target.getClass().getInterfaces(), handler);
        proxyObject.add("張玉龍");
        
        String path = "D:/$Proxy0.class";
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloworldImpl.class.getInterfaces());
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(path);
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }

   執行這段程式碼,會在D盤生成一個名為$Proxy0.class的檔案。通過反編譯工具,得到JDK為我們生成的代理類是這樣的:

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 

import com.zhb.jdk.proxy.IUserService;
import java.lang.reflect.*;

public final class $Proxy0 extends Proxy
    implements IUserService
{

    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    //代理類的建構函式,其引數正是是InvocationHandler例項,
    //Proxy.newInstance方法就是通過通過這個建構函式來建立代理例項的
    public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }
     // Object類中的三個方法,equals,toString, hashCode
    public final boolean equals(Object obj)
    {
        try
        {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    //介面代理方法
    public final void add(String s)
    {
        try
        {
            // invocation handler的 invoke方法在這裡被呼叫
            super.h.invoke(this, m3, new Object[] {
                s
            });
            return;
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            // 在這裡呼叫了invoke方法。
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    
    // 靜態程式碼塊對變數進行一些初始化工作
    static 
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.zhb.jdk.proxy.IUserService").getMethod("add", new Class[] {
                Class.forName("java.lang.String")
            });
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        }
        catch (NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch (ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

生成了Object類的三個方法:toString,hashCode,equals。還有我們需要被代理的方法。

 

JDK代理類的cache clear機制

大家都知道、在專案中被代理的class越來越多,所以jdk會搞一個cache的方式來防止相同的代理介面重複生成class,影響效能不說,實現也不是很優雅,那麼現在就會有一個問題了,當classloader已經在記憶體中沒有依賴的時候,被代理的proxy class其實也沒有什麼意義了,這樣就需要清空無用的cache,java Proxy採用了非常巧妙的“弱引用機制”,我們來看下面的程式碼

我們還是繼續看get方法的原始碼

 

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;
            }
        }
.......
}

其中原始碼中有一個方法expungeStaleEntries、我們進去這個方法一窺究竟

private void expungeStaleEntries() {
        CacheKey<K> cacheKey;
        while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {
            cacheKey.expungeFrom(map, reverseMap);
        }
    }

 在看看expungeFrom方法原始碼幹了些什麼

void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map,
                         ConcurrentMap<?, Boolean> reverseMap) {
            // removing just by key is always safe here because after a CacheKey
            // is cleared and enqueue-ed it is only equal to itself
            // (see equals method)...
            ConcurrentMap<?, ?> valuesMap = map.remove(this);
            // remove also from reverseMap if needed
            if (valuesMap != null) {
                for (Object cacheValue : valuesMap.values()) {
                    reverseMap.remove(cacheValue);
                }
            }
        }

  程式碼很清晰了,清空被代理的物件。現在的關鍵就是refQueue物件是怎麼來的。我們繼續找一下跟refQueue相關的原始碼、在get中還有一段程式碼是這樣的

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

 

private static final class CacheKey<K> extends WeakReference<K> {

        // a replacement for null keys
        private static final Object NULL_KEY = new Object();

        static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) {
            return key == null
                   // null key means we can't weakly reference it,
                   // so we use a NULL_KEY singleton as cache key
                   ? NULL_KEY
                   // non-null key requires wrapping with a WeakReference
                   : new CacheKey<>(key, refQueue);
        }

        private final int hash;

        private CacheKey(K key, ReferenceQueue<K> refQueue) {
            super(key, refQueue);
            this.hash = System.identityHashCode(key);  // compare by identity
        }
.....
}

 這樣看就非常清晰了、原來是CacheKey繼承了WeakReference弱引用機制,當弱引用依賴的key沒有引用的時候,當前失效的物件就會進入ReferenceQueue中來實現清空cache的功能、這種實現思路和ThreadLocal的實現原理是一樣的、大家有興趣可以去閱讀以下相關原始碼。

 

三:cglib代理原始碼分析

有了上面的原始碼分析經驗,聰明的小夥伴一定知道cglib代理實際上也差不多,只不過是基於Class類生成的,可以對類進行代理,無需介面,但是內部的實驗邏輯也比較複雜,先上一個簡單的demo

package cglib;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibTest implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println ("我被代理了");
        return proxy.invokeSuper ( obj,args );
    }

    public String hello(String name){
        return "你好" + name;
    }

    public static void main(String[] args) {
       System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );
       Enhancer enhancer = new Enhancer();
       enhancer.setSuperclass (CglibTest.class);
       enhancer.setCallback(new CglibTest());
       CglibTest cglibTest = (CglibTest) enhancer.create ();
       String result = cglibTest.hello ( "張玉龍" );
       System.out.println (result);
    }
}

執行結果

CGLIB debugging enabled, writing to '/Users/zhangyulong/Downloads'
我被代理了
你好張玉龍

”耳熟能詳“的生成結果,那麼接下來我們看看它到底是怎麼生成的,實現原理和Jdk代理有什麼不同?

我們一層一層的翻原始碼來看看

public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
    } 

 

classOnly程式碼是否只生成class,不生成代理物件,預設是false,說明要生成物件。argumentType是構造器引數型別,由於我們使用無參構造器,這些引數暫時可以忽略掉。

private Object createHelper() {
        preValidate();
        Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                ReflectUtils.getNames(interfaces),
                filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                callbackTypes,
                useFactory,
                interceptDuringConstruction,
                serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);
        return result;
    }

 preValidate 首先驗證一下引數型別以及基礎校驗,cglib支援CallbackFilter,由於我們callBack只有一個,enhancer.setCallback(new CglibTest()); 所以這裡預設沒有filter,看下cglib的處理

private void preValidate() {
        if (callbackTypes == null) {
            callbackTypes = CallbackInfo.determineTypes(callbacks, false);
            validateCallbackTypes = true;
        }
        if (filter == null) {
            if (callbackTypes.length > 1) {
                throw new IllegalStateException("Multiple callback types possible but no filter specified");
            }
            filter = ALL_ZERO;
        }
    }
private static final CallbackFilter ALL_ZERO = new CallbackFilter(){
public int accept(Method method) {
return 0;
}
};

  

預設返回0,就是我們傳入的new CglibTest()。重新返回主流程,我們看一下

Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                ReflectUtils.getNames(interfaces),
                filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                callbackTypes,
                useFactory,
                interceptDuringConstruction,
                serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);

 

首先根據代理類生成了一個key。這個key的主要作用就是對生成的代理類進行快取,生成程式碼在KeyFactory.create方法。這裡不是主線流程,感興趣的小夥伴自己深入一下即可

public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
                                    List<KeyFactoryCustomizer> next) {
        Generator gen = new Generator();
        gen.setInterface(keyInterface);

        if (customizer != null) {
            gen.addCustomizer(customizer);
        }
        if (next != null && !next.isEmpty()) {
            for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
                gen.addCustomizer(keyFactoryCustomizer);
            }
        }
        gen.setClassLoader(loader);
        return gen.create();
    }

 

我們主要看一下AbstractClassGenerator.create方法,這裡也是我們生成代理程式碼的主流程

protected Object create(Object key) {
        try {
            ClassLoader loader = getClassLoader();
            Map<ClassLoader, ClassLoaderData> cache = CACHE;
            ClassLoaderData data = cache.get(loader);
            if (data == null) {
                synchronized (AbstractClassGenerator.class) {
                    cache = CACHE;
                    data = cache.get(loader);
                    if (data == null) {
                        Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                        data = new ClassLoaderData(loader);
                        newCache.put(loader, data);
                        CACHE = newCache;
                    }
                }
            }
            this.key = key;
            Object obj = data.get(this, getUseCache());
            if (obj instanceof Class) {
                return firstInstance((Class) obj);
            }
            return nextInstance(obj);
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        }
    }

 聰明的小夥伴已經發現了,cglib代理以及jdk代理的快取結構大同小異。

private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>();

 1級快取, ClassLoader以及我們cglib的代理快取物件ClassLoaderData,在ClassLoaderData裡維護了一個弱引用的classloader物件,以及代理類的快取對偶性 LoadingCache。這和JDK代理弱引用classloader幾乎是完全一樣的

public ClassLoaderData(ClassLoader classLoader) {
            if (classLoader == null) {
                throw new IllegalArgumentException("classLoader == null is not yet supported");
            }
            this.classLoader = new WeakReference<ClassLoader>(classLoader);
            Function<AbstractClassGenerator, Object> load =
                    new Function<AbstractClassGenerator, Object>() {
                        public Object apply(AbstractClassGenerator gen) {
                            Class klass = gen.generate(ClassLoaderData.this);
                            return gen.wrapCachedClass(klass);
                        }
                    };
            generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
        }
public ClassLoader getClassLoader() {
return classLoader.get();
}

 上面我們講了JDK代理的快取清空的邏輯,那麼我們看下cglib代理物件時,classloader失效後如何處理的,畢竟是弱引用classloader,那麼一定要做快取清空處理的。

ClassLoader classLoader = data.getClassLoader();
            if (classLoader == null) {
                throw new IllegalStateException("ClassLoader is null while trying to define class " +
                        getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
                        "Please file an issue at cglib's issue tracker.");
            } 

cglib的處理還是比較暴力的,直接丟擲異常。接下來我們看下二級快取以及生成位元組碼的處理

public Object get(AbstractClassGenerator gen, boolean useCache) {
            if (!useCache) {
              return gen.generate(ClassLoaderData.this);
            } else {
              Object cachedValue = generatedClasses.get(gen);
              return gen.unwrapCachedValue(cachedValue);
            }
        }

 useCache來決定是否生成位元組碼後,每次都快取。 我們手動設定就可以了。

/**
     * Whether use and update the static cache of generated classes
     * for a class with the same properties. Default is <code>true</code>.
     */
    public void setUseCache(boolean useCache) {
        this.useCache = useCache;
    }

    /**
     * @see #setUseCache
     */
    public boolean getUseCache() {
        return useCache;
    }

  

Object cachedValue = generatedClasses.get(gen); 快取的邏輯分支,我們接著跟下去。

public V get(K key) {
        final KK cacheKey = keyMapper.apply(key);
        Object v = map.get(cacheKey);
        if (v != null && !(v instanceof FutureTask)) {
            return (V) v;
        }

        return createEntry(key, cacheKey, v);
    }

  邏輯非常清晰了,先看map中是否有cache物件。有直接拿出來,沒有通過createEntry(key, cacheKey, v)來生成即可。keyMapper.apply(key)是什麼呢,我們看看

private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
            public Object apply(AbstractClassGenerator gen) {
                return gen.key;
            }
        };

  gen.key就是我們上面提到的KeyFactory生成的key。生成代理物件,並且快取下來

protected V createEntry(final K key, KK cacheKey, Object v) {
        FutureTask<V> task;
        boolean creator = false;
        if (v != null) {
            // Another thread is already loading an instance
            task = (FutureTask<V>) v;
        } else {
            task = new FutureTask<V>(new Callable<V>() {
                public V call() throws Exception {
                    return loader.apply(key);
                }
            });
            Object prevTask = map.putIfAbsent(cacheKey, task);
            if (prevTask == null) {
                // creator does the load
                creator = true;
                task.run();
            } else if (prevTask instanceof FutureTask) {
                task = (FutureTask<V>) prevTask;
            } else {
                return (V) prevTask;
            }
        }

        V result;
        try {
            result = task.get();
        } catch (InterruptedException e) {
            throw new IllegalStateException("Interrupted while loading cache item", e);
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                throw ((RuntimeException) cause);
            }
            throw new IllegalStateException("Unable to load cache item", cause);
        }
        if (creator) {
            map.put(cacheKey, result);
        }
        return result;
    }

  到目前為止,我們快取相關的邏輯都已經講解完畢了,我們把精力放到生成位元組碼部分,最終生成位元組碼的方法如下

protected Class generate(ClassLoaderData data) {
        Class gen;
        Object save = CURRENT.get();
        CURRENT.set(this);
        try {
            ClassLoader classLoader = data.getClassLoader();
            if (classLoader == null) {
                throw new IllegalStateException("ClassLoader is null while trying to define class " +
                        getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
                        "Please file an issue at cglib's issue tracker.");
            }
            synchronized (classLoader) {
              String name = generateClassName(data.getUniqueNamePredicate());              
              data.reserveName(name);
              this.setClassName(name);
            }
            if (attemptLoad) {
                try {
                    gen = classLoader.loadClass(getClassName());
                    return gen;
                } catch (ClassNotFoundException e) {
                    // ignore
                }
            }
            byte[] b = strategy.generate(this);
            String className = ClassNameReader.getClassName(new ClassReader(b));
            ProtectionDomain protectionDomain = getProtectionDomain();
            synchronized (classLoader) { // just in case
                if (protectionDomain == null) {
                    gen = ReflectUtils.defineClass(className, b, classLoader);
                } else {
                    gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
                }
            }
            return gen;
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        } finally {
            CURRENT.set(save);
        }
    }

  先使用generateClassName生成代理類的名字,這裡就是我們debug Spring Aop原始碼以及其他原始碼中 帶$符號以及cglib很長的名稱。

private String generateClassName(Predicate nameTestPredicate) {
        return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate);
    }

  最關鍵的生成位元組碼的部分

byte[] b = strategy.generate(this);

public byte[] generate(ClassGenerator cg) throws Exception {
    DebuggingClassWriter cw = getClassVisitor();
    transform(cg).generateClass(cw);
    return transform(cw.toByteArray());
}

protected DebuggingClassWriter getClassVisitor() throws Exception {
  return new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
}

 

public byte[] toByteArray() {
        
      return (byte[]) java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction() {
            public Object run() {
                
                
                byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
                if (debugLocation != null) {
                    String dirs = className.replace('.', File.separatorChar);
                    try {
                        new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
                        
                        File file = new File(new File(debugLocation), dirs + ".class");
                        OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
                        try {
                            out.write(b);
                        } finally {
                            out.close();
                        }
                        
                        if (traceCtor != null) {
                            file = new File(new File(debugLocation), dirs + ".asm");
                            out = new BufferedOutputStream(new FileOutputStream(file));
                            try {
                                ClassReader cr = new ClassReader(b);
                                PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
                                ClassVisitor tcv = (ClassVisitor)traceCtor.newInstance(new Object[]{null, pw});
                                cr.accept(tcv, 0);
                                pw.flush();
                            } finally {
                                out.close();
                            }
                        }
                    } catch (Exception e) {
                        throw new CodeGenerationException(e);
                    }
                }
                return b;
             }  
            });
            
        }
    }

  

我們看到這裡可以將生成的程式碼放到指定的位置來方便檢視。這也就是我們demo中設定程式碼生成位置的原因,我們要看看它到底生成了什麼。

System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );

生成位元組碼的方法在Enhancer中

public void generateClass(ClassVisitor v) 

底層是通過asm工具來生成的位元組碼,然後通過構造器反射來生成的程式碼邏輯。由於程式碼生成部分比較複雜,我們忽略這一部分,只關注一下和CallBackFilter相關的內容。

private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) {

...........
 MethodInfo method = (MethodInfo)it1.next();
            Method actualMethod = (it2 != null) ? (Method)it2.next() : null;
            int index = filter.accept(actualMethod);
            if (index >= callbackTypes.length) {
                throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
            }
            originalModifiers.put(method, new Integer((actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers()));
            indexes.put(method, new Integer(index));
            List group = (List)groups.get(generators[index]);
            if (group == null) {
                groups.put(generators[index], group = new ArrayList(methods.size()));
            }
            group.add(method);
................

}

這裡我們可以看到生成代理類位元組碼時,根據我們傳入的CallbackFilter來決定使用哪個Callback。

看一下到底生成了哪些檔案。

CglibTest$$EnhancerByCGLIB$$fc037646.class
CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181.class
CglibTest$$FastClassByCGLIB$$ef5535a6.class

在目錄中我們發現生成了三個檔案。首先第一個是根據CglibTest原生類來生成的代理類,第二個是原生類的FastClass,第三個是代理類的FastClass

代理類

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package cglib;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibTest$$EnhancerByCGLIB$$fc037646 extends CglibTest implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$hello$0$Method;
    private static final MethodProxy CGLIB$hello$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$intercept$1$Method;
    private static final MethodProxy CGLIB$intercept$1$Proxy;
    private static final Method CGLIB$equals$2$Method;
    private static final MethodProxy CGLIB$equals$2$Proxy;
    private static final Method CGLIB$toString$3$Method;
    private static final MethodProxy CGLIB$toString$3$Proxy;
    private static final Method CGLIB$hashCode$4$Method;
    private static final MethodProxy CGLIB$hashCode$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("cglib.CglibTest$$EnhancerByCGLIB$$fc037646");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$2$Method = var10000[0];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[1];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[2];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[3];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
        var10000 = ReflectUtils.findMethods(new String[]{"hello", "(Ljava/lang/String;)Ljava/lang/String;", "intercept", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;"}, (var1 = Class.forName("cglib.CglibTest")).getDeclaredMethods());
        CGLIB$hello$0$Method = var10000[0];
        CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
        CGLIB$intercept$1$Method = var10000[1];
        CGLIB$intercept$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;", "intercept", "CGLIB$intercept$1");
    }

    final String CGLIB$hello$0(String var1) {
        return super.hello(var1);
    }

    public final String hello(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy) : super.hello(var1);
    }

    final Object CGLIB$intercept$1(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable {
        return super.intercept(var1, var2, var3, var4);
    }

    public final Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$intercept$1$Method, new Object[]{var1, var2, var3, var4}, CGLIB$intercept$1$Proxy) : super.intercept(var1, var2, var3, var4);
    }

    final boolean CGLIB$equals$2(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$3() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$4() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$5() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -1249666147:
            if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
                return CGLIB$intercept$1$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$5$Proxy;
            }
            break;
        case 848333779:
            if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
                return CGLIB$hello$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$2$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$3$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$4$Proxy;
            }
        }

        return null;
    }

    public CglibTest$$EnhancerByCGLIB$$fc037646() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        CglibTest$$EnhancerByCGLIB$$fc037646 var1 = (CglibTest$$EnhancerByCGLIB$$fc037646)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

 

 代理類的FastClass

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package cglib;

import cglib.CglibTest..EnhancerByCGLIB..fc037646;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.reflect.FastClass;

public class CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181 extends FastClass {
    public CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -2055565910:
            if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 3;
            }
            break;
        case -1457535688:
            if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                return 16;
            }
            break;
        case -1411812934:
            if (var10000.equals("CGLIB$hashCode$4()I")) {
                return 21;
            }
            break;
        case -1249666147:
            if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
                return 14;
            }
            break;
        case -894172689:
            if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 11;
            }
            break;
        case -879968516:
            if (var10000.equals("CGLIB$hello$0(Ljava/lang/String;)Ljava/lang/String;")) {
                return 17;
            }
            break;
        case -623122092:
            if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
                return 0;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return 9;
            }
            break;
        case -419626537:
            if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 1;
            }
            break;
        case 374345669:
            if (var10000.equals("CGLIB$equals$2(Ljava/lang/Object;)Z")) {
                return 19;
            }
            break;
        case 560567118:
            if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
                return 15;
            }
            break;
        case 811063227:
            if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 12;
            }
            break;
        case 848333779:
            if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
                return 13;
            }
            break;
        case 973717575:
            if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
                return 5;
            }
            break;
        case 1115619315:
            if (var10000.equals("CGLIB$intercept$1(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
                return 18;
            }
            break;
        case 1221173700:
            if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 10;
            }
            break;
        case 1230699260:
            if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
                return 4;
            }
            break;
        case 1341835395:
            if (var10000.equals("main([Ljava/lang/String;)V")) {
                return 23;
            }
            break;
        case 1517819849:
            if (var10000.equals("CGLIB$toString$3()Ljava/lang/String;")) {
                return 20;
            }
            break;
        case 1584330438:
            if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 2;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 6;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 7;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 8;
            }
            break;
        case 2011844968:
            if (var10000.equals("CGLIB$clone$5()Ljava/lang/Object;")) {
                return 22;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 7;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 6;
                    }
                }
            }
            break;
        case -1053468136:
            if (var1.equals("getCallbacks")) {
                switch(var2.length) {
                case 0:
                    return 5;
                }
            }
            break;
        case -981624788:
            if (var1.equals("CGLIB$intercept$1")) {
                switch(var2.length) {
                case 4:
                    if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) {
                        return 18;
                    }
                }
            }
            break;
        case -124978608:
            if (var1.equals("CGLIB$equals$2")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 19;
                    }
                }
            }
            break;
        case -60403779:
            if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 2;
                    }
                }
            }
            break;
        case -29025554:
            if (var1.equals("CGLIB$hashCode$4")) {
                switch(var2.length) {
                case 0:
                    return 21;
                }
            }
            break;
        case 3343801:
            if (var1.equals("main")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Ljava.lang.String;")) {
                        return 23;
                    }
                }
            }
            break;
        case 85179481:
            if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 3;
                    }
                }
            }
            break;
        case 94756189:
            if (var1.equals("clone")) {
                switch(var2.length) {
                case 0:
                    return 9;
                }
            }
            break;
        case 99162322:
            if (var1.equals("hello")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.String")) {
                        return 13;
                    }
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 8;
                }
            }
            break;
        case 161998109:
            if (var1.equals("CGLIB$STATICHOOK1")) {
                switch(var2.length) {
                case 0:
                    return 16;
                }
            }
            break;
        case 495524492:
            if (var1.equals("setCallbacks")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 1;
                    }
                }
            }
            break;
        case 502538434:
            if (var1.equals("intercept")) {
                switch(var2.length) {
                case 4:
                    if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) {
                        return 14;
                    }
                }
            }
            break;
        case 1154623345:
            if (var1.equals("CGLIB$findMethodProxy")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
                        return 0;
                    }
                }
            }
            break;
        case 1543336190:
            if (var1.equals("CGLIB$toString$3")) {
                switch(var2.length) {
                case 0:
                    return 20;
                }
            }
            break;
        case 1811874389:
            if (var1.equals("newInstance")) {
                switch(var2.length) {
                case 1:
                    String var10001 = var2[0].getName();
                    switch(var10001.hashCode()) {
                    case -845341380:
                        if (var10001.equals("net.sf.cglib.proxy.Callback")) {
                            return 11;
                        }
                        break;
                    case 1730110032:
                        if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
                            return 10;
                        }
                    }
                case 2:
                default:
                    break;
                case 3:
                    if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 12;
                    }
                }
            }
            break;
        case 1817099975:
            if (var1.equals("setCallback")) {
                switch(var2.length) {
                case 2:
                    if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
                        return 15;
                    }
                }
            }
            break;
        case 1891304123:
            if (var1.equals("CGLIB$hello$0")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.String")) {
                        return 17;
                    }
                }
            }
            break;
        case 1905679803:
            if (var1.equals("getCallback")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("int")) {
                        return 4;
                    }
                }
            }
            break;
        case 1951977611:
            if (var1.equals("CGLIB$clone$5")) {
                switch(var2.length) {
                case 0:
                    return 22;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        fc037646 var10000 = (fc037646)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                return fc037646.CGLIB$findMethodProxy((Signature)var3[0]);
            case 1:
                var10000.setCallbacks((Callback[])var3[0]);
                return null;
            case 2:
                fc037646.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 3:
                fc037646.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 4:
                return var10000.getCallback(((Number)var3[0]).intValue());
            case 5:
                return var10000.getCallbacks();
            case 6:
                return new Boolean(var10000.equals(var3[0]));
            case 7:
                return var10000.toString();
            case 8:
                return new Integer(var10000.hashCode());
            case 9:
                return var10000.clone();
            case 10:
                return var10000.newInstance((Callback[])var3[0]);
            case 11:
                return var10000.newInstance((Callback)var3[0]);
            case 12:
                return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
            case 13:
                return var10000.hello((String)var3[0]);
            case 14:
                return var10000.intercept(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]);
            case 15:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                return null;
            case 16:
                fc037646.CGLIB$STATICHOOK1();
                return null;
            case 17:
                return var10000.CGLIB$hello$0((String)var3[0]);
            case 18:
                return var10000.CGLIB$intercept$1(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]);
            case 19:
                return new Boolean(var10000.CGLIB$equals$2(var3[0]));
            case 20:
                return var10000.CGLIB$toString$3();
            case 21:
                return new Integer(var10000.CGLIB$hashCode$4());
            case 22:
                return var10000.CGLIB$clone$5();
            case 23:
                CglibTest.main((String[])var3[0]);
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        fc037646 var10000 = new fc037646;
        fc037646 var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 23;
    }
}

  

 原生類的FastClass

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package cglib;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.reflect.FastClass;

public class CglibTest$$FastClassByCGLIB$$ef5535a6 extends FastClass {
    public CglibTest$$FastClassByCGLIB$$ef5535a6(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1249666147:
            if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
                return 2;
            }
            break;
        case 848333779:
            if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
                return 1;
            }
            break;
        case 1341835395:
            if (var10000.equals("main([Ljava/lang/String;)V")) {
                return 0;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 3;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 4;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 5;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 4;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 3;
                    }
                }
            }
            break;
        case 3343801:
            if (var1.equals("main")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Ljava.lang.String;")) {
                        return 0;
                    }
                }
            }
            break;
        case 99162322:
            if (var1.equals("hello")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.String")) {
                        return 1;
                    }
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 5;
                }
            }
            break;
        case 502538434:
            if (var1.equals("intercept")) {
                switch(var2.length) {
                case 4:
                    if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) {
                        return 2;
                    }
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        CglibTest var10000 = (CglibTest)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                CglibTest.main((String[])var3[0]);
                return null;
            case 1:
                return var10000.hello((String)var3[0]);
            case 2:
                return var10000.intercept(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]);
            case 3:
                return new Boolean(var10000.equals(var3[0]));
            case 4:
                return var10000.toString();
            case 5:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        CglibTest var10000 = new CglibTest;
        CglibTest var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 5;
    }
}

  

我們看下代理類的hello方法

public final String hello(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy) : super.hello(var1);
    }

  最終呼叫了 var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy)方法,也就是我們的

@Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println ("我被代理了");
        return proxy.invokeSuper ( obj,args );
    }

proxy.invokeSuper ( obj,args ) 是怎麼實現的呢,接下來我們重點看看 CGLIB$hello$0$Proxy的生成邏輯。

CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
    MethodProxy proxy = new MethodProxy();
    proxy.sig1 = new Signature(name1, desc);
    proxy.sig2 = new Signature(name2, desc);
    proxy.createInfo = new CreateInfo(c1, c2);
    return proxy;
}

  

這裡根據代理類以及原生類的hello方法生成了方法簽名 Signature。

5個引數分別是 Class c1 目標類Class,Class c2 代理類Class,String desc 代理方法的描述,String name1 被代理方法名,String name2 代理方法名

接下來

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

 

private void init()
    {
        /* 
         * Using a volatile invariant allows us to initialize the FastClass and
         * method index pairs atomically.
         * 
         * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
         * code could allow fastClassInfo to be instantiated more than once, which
         * appears to be benign.
         */
        if (fastClassInfo == null)
        {
            synchronized (initLock)
            {
                if (fastClassInfo == null)
                {
                    CreateInfo ci = createInfo;

                    FastClassInfo fci = new FastClassInfo();
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(sig1);
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                }
            }
        }
    }

    private static class FastClassInfo
    {
        FastClass f1;
        FastClass f2;
        int i1;
        int i2;
    }

    private static class CreateInfo
    {
        Class c1;
        Class c2;
        NamingPolicy namingPolicy;
        GeneratorStrategy strategy;
        boolean attemptLoad;
        
        public CreateInfo(Class c1, Class c2)
        {
            this.c1 = c1;
            this.c2 = c2;
            AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
            if (fromEnhancer != null) {
                namingPolicy = fromEnhancer.getNamingPolicy();
                strategy = fromEnhancer.getStrategy();
                attemptLoad = fromEnhancer.getAttemptLoad();
            }
        }
    }

    private static FastClass helper(CreateInfo ci, Class type) {
        FastClass.Generator g = new FastClass.Generator();
        g.setType(type);
        g.setClassLoader(ci.c2.getClassLoader());
        g.setNamingPolicy(ci.namingPolicy);
        g.setStrategy(ci.strategy);
        g.setAttemptLoad(ci.attemptLoad);
        return g.create();
    }

 

其實這裡最主要的就是生成代理類和普通類的FastClass,以及hello方法的index,然後去呼叫,我們看一下簡單的例子來看看FastClass底層倒底是什麼

public class FastClass1 {

    public void hello(String name) {
        System.out.println("hello, " + name);
    }
    
    public void hi(String msg) {
        System.out.println("hi, " + msg);
    }
}

public class FastClass2 {
    
    public Object invoke(Object obj, int methodIndex, Object[] parameters) {
        FastClass1 target = (FastClass1)obj;
        Object result = null;
        switch (methodIndex) {
        case 1:
            target.hello((String)parameters[0]);
            break;
        case 2:
            target.hi((String)parameters[0]);
            break;
        }
        return result;
    }
    
    public int getIndex(String methodDescriptor) {
        switch (methodDescriptor.hashCode()) {
        case -2084786067:
            return 1;
        case -70025314:
            return 2;
        }
        return -1;
    }
}

public class FastClassTest {
    public static void main(String[] args) {
        FastClass1 fastClass1 = new FastClass1();
        FastClass2 fastClass2 = new FastClass2();
        int helloIndex = fastClass2.getIndex("hello(Ljava/lang/String;)V");//方法名(引數型別;...)返回型別
        fastClass2.invoke(fastClass1, helloIndex, new Object[]{"張三"});
        int hiIndex = fastClass2.getIndex("hi(Ljava/lang/String;)V");
        fastClass2.invoke(fastClass1, hiIndex, new Object[]{"cglib動態代理"});
    }
}

上例中,FastClass2是FastClass1的Fastclass,在FastClass2中有兩個方法getIndex和invoke。在getIndex方法中對FastClass1的每個方法建立索引,並根據入參(方法名+方法的描述符)來返回相應的索引。invoke根據指定的索引,以parameters為入參呼叫物件obj的方法。這樣就避免了反射呼叫,提高了效率。我們生成的CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181.class以及CglibTest$$FastClassByCGLIB$$ef5535a6.class 原理也是類似。
MethodProxy中invokeSuper 和MethodProxy中invoke的區別是什麼 我們來看看

public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (IllegalArgumentException e) {
            if (fastClassInfo.i1 < 0)
                throw new IllegalArgumentException("Protected method: " + sig1);
            throw e;
        }
    }


public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
fci.f1.invoke(fci.i1, obj, args);執行原生類Fastclass的hello方法
fci.f2.invoke(fci.i2, obj, args);執行代理類FastClass的hello方法

經常有小夥伴不小心用錯的邏輯,導致死迴圈。
@Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println ("我被代理了");
        return proxy.invoke ( obj,args );
    }

.........
我被代理了
我被代理了
我被代理了
Exception in thread "main" java.lang.StackOverflowError
	at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
	at sun.nio.cs.UTF_8.access$200(UTF_8.java:57)
	at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:636)
	at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
	at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
	at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
	at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
	at java.io.PrintStream.write(PrintStream.java:526)
	at java.io.PrintStream.print(PrintStream.java:669)
	at java.io.PrintStream.println(PrintStream.java:806)
	at cglib.CglibTest.intercept(CglibTest.java:13)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at cglib.CglibTest.intercept(CglibTest.java:14)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at cglib.CglibTest.intercept(CglibTest.java:14)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at cglib.CglibTest.intercept(CglibTest.java:14)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at cglib.CglibTest.intercept(CglibTest.java:14)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at cglib.CglibTest.intercept(CglibTest.java:14)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at cglib.CglibTest.intercept(CglibTest.java:14)
	at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
	at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
.........

為什麼會這樣,因為invokeSuper執行的是代理類的FastClass的方法,invoke是執行的原生類的FastClass的方法,

CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");

 最終執行的方法不一樣,分別是hello以及CGLIB$hello$0

final String CGLIB$hello$1(String var1) {
        return super.hello(var1);
    }

    public final String hello(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$1$Method, new Object[]{var1}, CGLIB$hello$1$Proxy) : super.hello(var1);
    }

執行CGLIB$hello$1方法最終呼叫原生方法,執行hello方法會一直執行MethodInterceptor的intercept方法導致死迴圈,最後還有一點攔截器在cglib中可以實現很多型別,這個也是在位元組碼生成程式碼中來實現的,Spring等框架常用的就MethodInterceptor

class CallbackInfo
{
private static final CallbackInfo[] CALLBACKS = {
        new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE),
        new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE),
        new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE),
        new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE),
        new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE),
        new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE),
        new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE),
    };
}

我們常用的callBack就是MethodInterceptor,但是其他的可能不太常用,他們的區別是什麼呢,來看下面的程式碼

package cglib.callback;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.*;

import java.lang.reflect.Method;

public class CglibTestCallBack  {

    public String hello0(String name){
        return "你好0" + name;
    }

    public String hello1(String name){
        return "你好1" + name;
    }

    public String hello2(String name){
        return "你好2" + name;
    }

    public String hello3(String name){
        return "你好3" + name;
    }

    public String hello4(String name){
        return "你好4" + name;
    }

    public String hello5(String name){
        return "你好5" + name;
    }

    public String hello6(String name){
        return "你好6" + name;
    }

    public static void main(String[] args) {
       System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );
       Enhancer enhancer = new Enhancer();
       enhancer.setSuperclass ( CglibTestCallBack.class);
       enhancer.setCallbacks(
               new Callback[]{
                       new DispatcherCallBack(),
                       new FixedValueCallBack(),
                       new InvocationHandlerCallback(),
                       new LazyLoaderCallBack(),
                       new MethodInterceptorCallBack(),
                       new NoOpCallBack(),
                       new ProxyRefDispatcherCallBack()
               }
             );
        enhancer.setCallbackFilter ( new CallbackFilter () {
            @Override
            public int accept(Method method) {
                String name = method.getName ();
                if(!name.startsWith ( "hello" )) return 0;

                String num = name.substring ( "hello".length () );
                return Integer.parseInt ( num );
            }
        } );

       CglibTestCallBack cglibTest = (CglibTestCallBack) enhancer.create ();
       String result = cglibTest.hello1 ( "張玉龍" );
       System.out.println (result);
    }
}

 

public class DispatcherCallBack implements Dispatcher {

    @Override
    public Object loadObject() throws Exception {
        return null;
    }
}

public class FixedValueCallBack implements FixedValue {
    @Override
    public Object loadObject() throws Exception {
        return null;
    }
}

public class InvocationHandlerCallback implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

public class LazyLoaderCallBack implements LazyLoader {

    @Override
    public Object loadObject() throws Exception {
        return null;
    }
}

public class NoOpCallBack implements NoOp {

}

public class ProxyRefDispatcherCallBack implements ProxyRefDispatcher {
    @Override
    public Object loadObject(Object proxy) throws Exception {
        return null;
    }
}

 

我們設定了六個callBack,對應了六個方法 hello0-6, 我們來看看他們生成的代理類的方法是什麼樣的,下面是代理類的部分程式碼

public final String hello0(String var1) {
        Dispatcher var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return ((CglibTestCallBack)var10000.loadObject()).hello0(var1);
    }

public final String hello1(String var1) {
        FixedValue var10000 = this.CGLIB$CALLBACK_1;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_1;
        }

        return (String)var10000.loadObject();
    }

public final String hello2(String var1) {
        try {
            InvocationHandler var10000 = this.CGLIB$CALLBACK_2;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_2;
            }

            return (String)var10000.invoke(this, CGLIB$hello2$1, new Object[]{var1});
        } catch (Error | RuntimeException var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

public final String hello3(String var1) {
        return ((CglibTestCallBack)this.CGLIB$LOAD_PRIVATE_3()).hello3(var1);
    }

    private final synchronized Object CGLIB$LOAD_PRIVATE_3() {
        Object var10000 = this.CGLIB$LAZY_LOADER_3;
        if (var10000 == null) {
            LazyLoader var10001 = this.CGLIB$CALLBACK_3;
            if (var10001 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10001 = this.CGLIB$CALLBACK_3;
            }

            var10000 = this.CGLIB$LAZY_LOADER_3 = var10001.loadObject();
        }

        return var10000;
    }

public final String hello4(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_4;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_4;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello4$3$Method, new Object[]{var1}, CGLIB$hello4$3$Proxy) : super.hello4(var1);
    }

public final String hello6(String var1) {
        ProxyRefDispatcher var10000 = this.CGLIB$CALLBACK_6;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_6;
        }

        return ((CglibTestCallBack)var10000.loadObject(this)).hello6(var1);
    }

無需多解釋,生成的程式碼非常清晰了,由於hello5是實現了NoOp,代理類忽略這個方法,直接呼叫原生類的hello5。值得注意的是CGLIB$BIND_CALLBACKS(this);這個方法是這些代理方法中統一的設定callback的方法,我們看看它到底幹了些什麼。

private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        CglibTestCallBack$$EnhancerByCGLIB$$58712cb6 var1 = (CglibTestCallBack$$EnhancerByCGLIB$$58712cb6)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            Callback[] var10001 = (Callback[])var10000;
            var1.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)((Callback[])var10000)[6];
            var1.CGLIB$CALLBACK_5 = (NoOp)var10001[5];
            var1.CGLIB$CALLBACK_4 = (MethodInterceptor)var10001[4];
            var1.CGLIB$CALLBACK_3 = (LazyLoader)var10001[3];
            var1.CGLIB$CALLBACK_2 = (InvocationHandler)var10001[2];
            var1.CGLIB$CALLBACK_1 = (FixedValue)var10001[1];
            var1.CGLIB$CALLBACK_0 = (Dispatcher)var10001[0];
        }

    }

 程式碼非常簡單,就是從CGLIB$THREAD_CALLBACKS 或者CGLIB$STATIC_CALLBACKS中獲取callBack陣列,那麼這個陣列我們什麼時候設定的呢?看下面程式碼 net.sf.cglib.proxy.Enhancer#firstInstance

protected Object firstInstance(Class type) throws Exception {
        if (classOnly) {
            return type;
        } else {
            return createUsingReflection(type);
        }
    }

private Object createUsingReflection(Class type) {
        setThreadCallbacks(type, callbacks);
        try{
        
        if (argumentTypes != null) {
        	
             return ReflectUtils.newInstance(type, argumentTypes, arguments);
             
        } else {
        	
            return ReflectUtils.newInstance(type);
            
        }
        }finally{
         // clear thread callbacks to allow them to be gc'd
         setThreadCallbacks(type, null);
        }
    }

private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS";

private static void setThreadCallbacks(Class type, Callback[] callbacks) {
        setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME);
    }

 特別明顯在初始化時,將我們設定的callBack陣列設定到代理類中,並且在代理類生成例項之後,再清空,方便gc回收,到此cglib的原始碼解析就已經完成了。這裡有一個細節就是上面的程式碼 只有hello4方法才會生成FastClass,所以我們生成的代理類只有1個,沒有生成原生類和代理的FsstClass,這是因為fastclass的生成只有首次呼叫方法的時候,才會去觸發。

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

所以當我們呼叫hello4方法時,首次呼叫就會生成代理類了。這也就是為什麼cglib代理首次呼叫的時候速度會慢一些,因為要先生成位元組碼。

四:手把手寫基於介面的java代理

上面我們分析了jdk動態代理原始碼、cglib代理原始碼、那我們是不是可以自己用自己的方式去寫一個屬於自己的jdk代理呢,答案是可以的

首先我們寫一個基類,當然我並沒有在基類裡面寫什麼東西,只是模擬java中的proxy類而已,當然我們也可以豐富的去拓展一下這個類的方法,來實現更多的功能,讀者可以通過讀完這篇文章之後自己去考慮一下如何來拓展。

1 package meituan.zylproxy.handlder;
2 public class ZylProxy {
3     public ZylProxy(){
4     }
5 }

 

代理的核心介面,我們去做代理的時候一定是通過反射去呼叫的,不管jdk也好還是cglib也好,永遠也無法脫離反射,我們照貓畫虎,自己寫一個代理介面核心類,這並不是什麼難題,看起來和jdk的核心類介面也沒有什麼區別。

1 package meituan.zylproxy.handlder;
2 
3 import java.lang.reflect.Method;
4 
5 public interface ZYLInvocationHandler {
6 
7     public Object invoke(Object proxy, Method method, Object[] args)
8         throws Exception;
9 }

說明一下 第一個引數proxy是代表代理類,而不是使用者自己寫的原生類實現。引數Method是介面的方法,args是執行時引數列表,在執行時傳遞過來的實際上就是實現類的引數,好了,下面讓我們去深入核心。

我們自定義兩個介面和介面的實現Idto,Idto2,和Dtoimpl如下:

1 package meituan.zylproxy.test.i;
2 
3 public interface Idto {
4 
5     public void add();
6     
7     public String get();
8     
9 }
package meituan.zylproxy.test.i;

public interface Idto2 {

    public void adda();
    
    public String geta();
    
}
package meituan.zylproxy.test.i.impl;

import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.Idto2;

public class DtoImpl implements Idto,Idto2{

    @Override
    public void add() {
        System.out.println("add");
        
    }

    @Override
    public String get() {
        System.out.println("get");
        return "return get";
    }

    @Override
    public void adda() {
        System.out.println("adda");
    }

    @Override
    public String geta() {
        System.out.println("geta");
        return "return geta";
    }

}

這是幾個再簡單不過的介面和實現類了,也沒有什麼可說的。接下來我們想對介面進行代理,無非是我們動態將介面進行實現,從而達到對使用者進行自定義handle介面暴露而已,下面看一下我們需要生成一個什麼樣的代理類。

import java.lang.reflect.Method;

import meituan.zylproxy.handlder.ZylProxy;
import meituan.zylproxy.handlder.ZYLInvocationHandler;
import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.Idto2;

public class IdtoPorxy extends ZylProxy implements Idto, Idto2 {
    public ZYLInvocationHandler zYLInvocationHandler;
    public static Method add1;
    public static Method get2;
    public static Method adda3;
    public static Method geta4;

    static {
        try {
            add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] );
            get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] );
            adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] );
            geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] );
        } catch (Exception e) {
        }
    }

    public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) {
        this.zYLInvocationHandler = zYLInvocationHandler;
    }

    public void add() {
        Object[] o = {};
        try {
            this.zYLInvocationHandler.invoke ( this, add1, o );
            return;
        } catch (Throwable e) {
            e.printStackTrace ();
        }
    }

    public java.lang.String get() {
        Object[] o = {};
        try {
            return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o );
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return null;
    }

    public void adda() {
        Object[] o = {};
        try {
            this.zYLInvocationHandler.invoke ( this, adda3, o );
            return;
        } catch (Throwable e) {
            e.printStackTrace ();
        }
    }

    public java.lang.String geta() {
        Object[] o = {};
        try {
            return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o );
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return null;
    }
}

這個類不是由使用者寫的,而是我們動態生成的,對於jdk來說是生成了位元組碼,對cglib來說是通過位元組碼增強,其實實現的方式有多種,後面為了更方便大家理解我用字串的形式來動態生成這麼一個"傢伙",先看看這個類幹了些什麼吧,也很簡單。

public class IdtoPorxy extends ZylProxy implements Idto, Idto2

首先是繼承了剛才我們所說的ZylProxy,留著今後拓展,可以參照java的Proxy,然後並且動態的實現了這兩個介面。很簡單

public ZYLInvocationHandler zYLInvocationHandler;
public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) {
this.zYLInvocationHandler = zYLInvocationHandler;
}

這個是通過建構函式傳進來一個handler物件,對實現類的操作都靠它了。

public static Method add1;
    public static Method get2;
    public static Method adda3;
    public static Method geta4;

    static {
        try {
            add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] );
            get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] );
            adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] );
            geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] );
        } catch (Exception e) {
        }
    }

枚舉出來所有的介面的方法,通過class.forname來獲取到Method元資料。備用

 

public void add() {
        Object[] o = {};
        try {
            this.zYLInvocationHandler.invoke ( this, add1, o );
            return;
        } catch (Throwable e) {
            e.printStackTrace ();
        }
    }

    public java.lang.String get() {
        Object[] o = {};
        try {
            return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o );
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return null;
    }

    public void adda() {
        Object[] o = {};
        try {
            this.zYLInvocationHandler.invoke ( this, adda3, o );
            return;
        } catch (Throwable e) {
            e.printStackTrace ();
        }
    }

    public java.lang.String geta() {
        Object[] o = {};
        try {
            return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o );
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return null;
    }

上面是要枚舉出來所有的方法的實現,很簡單都一個模樣,把實現交給handler去做就可以了。至於怎麼實現靠handler,我們動態生成的這個類只負責委託,不做任何事情。看到這裡大家一定急不可待的想知道這個類怎麼生成的了,我把我寫的原始碼給大家貼出來看一下。

package meituan.zylproxy.util;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.Idto2;

public class ClassUtil {

    public static String mackProxyClass(Class<?> c) throws Exception{
        if(!c.isInterface()){
            throw new Exception("代理的類必須是介面");
        }

        StringBuffer importsp = new StringBuffer();
        importsp.append("import java.lang.reflect.Method;\n");
        importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n");
        importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n");

        importsp.append("import " +c.getName() + ";\n");

        StringBuilder publicStaticMethods = new StringBuilder();
        
        //public static Method add;
        StringBuilder publicMethods = new StringBuilder();
        publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n");

        StringBuilder constructorsp = new StringBuilder();
        String interFaceName = c.getName().substring(c.getName().lastIndexOf(".")+1);
        constructorsp.append("public ").append("" + interFaceName + "Porxy").
                   append("(ZYLInvocationHandler zYLInvocationHandler) { "
                           + "this.zYLInvocationHandler = zYLInvocationHandler;"
                           + "}");

        publicStaticMethods.append(" static { try {  ");

        StringBuilder classsp = new StringBuilder();
        classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements ").append(interFaceName).append("{");
        
     
        StringBuilder allMethods = new StringBuilder();
        Method[] Methods = c.getMethods();
        
        int curr=0;
        for (Method m_:Methods) {
            curr++;
            publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n");
            
            publicStaticMethods.append("").append(m_.getName() +  String.valueOf(curr)).append("=");

            publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", ");
            
            StringBuilder sp =new StringBuilder();
            StringBuilder spArgs = new StringBuilder();
            spArgs.append("Object[] o ={");
            //public
             sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" ");
            //void | java.lang.String
            sp.append(m_.getReturnType().getName()).append(" ");
            //add()|get()
            sp.append(m_.getName().concat("("));

            StringBuilder methodCLass = new StringBuilder();
             if(m_.getParameterTypes().length>0){
                Class<?>[] claszz = m_.getParameterTypes();
                int methodOffset = 0;
                methodCLass.append("new Class[] { ");
                for (Class<?> c_ : claszz) {
                    String paramStr = "obj" + String.valueOf(++methodOffset);
                    spArgs.append(paramStr.concat(","));
                    sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(",");
                    methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),");
                }
                sp = new StringBuilder(sp.substring(0, sp.length()-1));
                 spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1));
                 methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1));
            }

             if(methodCLass.length()>0){
                 methodCLass.append("}");
             } else{
                 methodCLass.append("new Class[0]");
             }
             sp.append("){\n");
            spArgs.append("}");
            sp.append(spArgs+";\n");
            
            if(sp.toString().contains("void")){
                sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n");
                sp.append("} catch (Throwable e) {e.printStackTrace();}}");

            } else{
                sp.append("try {return "
                        + "("
                        + m_.getReturnType().getName()
                        + ")"
                        + "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n");
            
                sp.append("} catch (Exception e) {e.printStackTrace();} return null;");

            }

            publicStaticMethods.append(methodCLass).append(");\n");
             allMethods.append(sp);
        }
        publicStaticMethods.append("} catch(Exception e){}}");
        classsp.append(publicMethods)
               .append(publicStaticMethods)
               .append(constructorsp).append(allMethods).append("}");
        classsp.append("}");
        importsp.append(classsp);
        return importsp.toString();
     }

    
    public static String mackMultiProxyClass(Class<?>[] cs) throws Exception{

        StringBuffer importsp = new StringBuffer();
        importsp.append("import java.lang.reflect.Method;\n");
        importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n");
        importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n");
        
        StringBuilder publicStaticMethods = new StringBuilder();
        publicStaticMethods.append(" static { try {  ");
        
        //public static Method add;
        StringBuilder publicMethods = new StringBuilder();
        publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n");
                
        int curr=0;
        
        StringBuilder constructorsp = new StringBuilder();
        String interFaceName = cs[0].getName().substring(cs[0].getName().lastIndexOf(".")+1);
        constructorsp.append("public ").append("" + interFaceName + "Porxy").
                   append("(ZYLInvocationHandler zYLInvocationHandler) { "
                           + "this.zYLInvocationHandler = zYLInvocationHandler;"
                           + "}");
        
        StringBuilder allMethods = new StringBuilder();
        
        StringBuilder classsp = new StringBuilder();
        classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements ");
        
        for (Class<?> c:cs) {
            if(!c.isInterface()){
                throw new Exception("代理的類必須是介面");
            }
            
            classsp.append(c.getName().substring(c.getName().lastIndexOf(".")+1)).append(",");
            
            importsp.append("import " +c.getName() + ";\n");
            
            
            Method[] Methods = c.getMethods();
            
            
            for (Method m_:Methods) {
                   curr++;
                publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n");
                
                publicStaticMethods.append("").append(m_.getName() +  String.valueOf(curr)).append("=");

                publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", ");
                
                StringBuilder sp =new StringBuilder();
                StringBuilder spArgs = new StringBuilder();
                spArgs.append("Object[] o ={");
                //public
                 sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" ");
                //void | java.lang.String
                sp.append(m_.getReturnType().getName()).append(" ");
                //add()|get()
                sp.append(m_.getName().concat("("));

                StringBuilder methodCLass = new StringBuilder();
                 if(m_.getParameterTypes().length>0){
                    Class<?>[] claszz = m_.getParameterTypes();
                    int methodOffset = 0;
                    methodCLass.append("new Class[] { ");
                    for (Class<?> c_ : claszz) {
                        String paramStr = "obj" + String.valueOf(++methodOffset);
                        spArgs.append(paramStr.concat(","));
                        sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(",");
                        methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),");
                    }
                    sp = new StringBuilder(sp.substring(0, sp.length()-1));
                     spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1));
                     methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1));
                }

                 if(methodCLass.length()>0){
                     methodCLass.append("}");
                 } else{
                     methodCLass.append("new Class[0]");
                 }
                 sp.append("){\n");
                spArgs.append("}");
                sp.append(spArgs+";\n");
                
                if(sp.toString().contains("void")){
                    sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n");
                    sp.append("} catch (Throwable e) {e.printStackTrace();}}");

                } else{
                    sp.append("try {return "
                            + "("
                            + m_.getReturnType().getName()
                            + ")"
                            + "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n");
                
                    sp.append("} catch (Exception e) {e.printStackTrace();} return null;}");

                }

                publicStaticMethods.append(methodCLass).append(");\n");
                 allMethods.append(sp);
            }
            
        }
        
        classsp = new StringBuilder(classsp.substring(0, classsp.length()-1)).append("{");
         
        publicStaticMethods.append("} catch(Exception e){}}");
        classsp.append(publicMethods)
               .append(publicStaticMethods)
               .append(constructorsp).append(allMethods).append("");
        classsp.append("}");
        importsp.append(classsp);
        return importsp.toString();
     }
    
    
    public static void main(String[] args) throws Exception {
        System.out.println(mackMultiProxyClass(new Class<?>[]{Idto.class}));
    }
}

看起來很複雜,仔細看一下就看了那麼幾個事情,把一個介面class或者多個介面class變成純字串的過程,一共兩個方法,一個是單介面的實現,很早之前寫的,第二個方法是多介面的實現支援多介面,只需要傳一個class物件就會生成代理類的字串,這裡僅僅是字串,需要編譯成class使用。那麼如何編譯成class呢。通過java中的工具類 JavaCompiler很簡單的就可以生成了。我們來看兩個工具類實現

package meituan.zylproxy;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.file.WatchEvent.Kind;
import java.util.HashMap;
import java.util.Map;

import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;

@SuppressWarnings("unchecked")
final class MemoryJavaFileManager extends ForwardingJavaFileManager {

    private final static String EXT = ".java";

    private Map<String, byte[]> classBytes;

    public MemoryJavaFileManager(JavaFileManager fileManager) {
        super(fileManager);
        classBytes = new HashMap<String, byte[]>();
    }

    public Map<String, byte[]> getClassBytes() {
        return classBytes;
    }

    public void close() throws IOException {
        classBytes = new HashMap<String, byte[]>();
    }

    public void flush() throws IOException {
    }
 
    private static class StringInputBuffer extends SimpleJavaFileObject {
        final String code;

        StringInputBuffer(String name, String code) {
            super(toURI(name), Kind.SOURCE);
            this.code = code;
        }

        public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
            return CharBuffer.wrap(code);
        }

        public Reader openReader() {
            return new StringReader(code);
        }
    }
 
    private class ClassOutputBuffer extends SimpleJavaFileObject {
        private String name;

        ClassOutputBuffer(String name) {
            super(toURI(name), Kind.CLASS);
            this.name = name;
        }

        public OutputStream openOutputStream() {
            return new FilterOutputStream(new ByteArrayOutputStream()) {
                public void close() throws IOException {
                    out.close();
                    ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
                    classBytes.put(name, bos.toByteArray());
                }
            };
        }
    }

    public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
                                               String className,
                                               JavaFileObject.Kind kind,
                                               FileObject sibling) throws IOException {
        if (kind == JavaFileObject.Kind.CLASS) {
            return new ClassOutputBuffer(className);
        } else {
            return super.getJavaFileForOutput(location, className, kind, sibling);
        }
    }

    static JavaFileObject makeStringSource(String name, String code) {
        return new StringInputBuffer(name, code);
    }

    static URI toURI(String name) {
        File file = new File(name);
        if (file.exists()) {
            return file.toURI();
        } else {
            try {
                final StringBuilder newUri = new StringBuilder();
                newUri.append("mfm:///");
                newUri.append(name.replace('.', '/'));
                if (name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT);
                return URI.create(newUri.toString());
            } catch (Exception exp) {
                return URI.create("mfm:///com/sun/script/java/java_source");
            }
        }
    }
}

 

package meituan.zylproxy;

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class DynamicLoader {

    public static Map<String, byte[]> compile(String javaSrc) {
        Pattern pattern = Pattern.compile("public\\s+class\\s+(\\w+)");

        Matcher matcher = pattern.matcher(javaSrc);

        if (matcher.find())
            return compile(matcher.group(1) + ".java", javaSrc);
        return null;
    }
    

    public static Map<String, byte[]> compile(String javaName, String javaSrc) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null);

        try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) {
            JavaFileObject javaFileObject = manager.makeStringSource(javaName, javaSrc);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));
            if (task.call())
                return manager.getClassBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static class MemoryClassLoader extends URLClassLoader {

        Map<String, byte[]> classBytes = new HashMap<String, byte[]>();

        public MemoryClassLoader(Map<String, byte[]> classBytes) {
            super(new URL[0], MemoryClassLoader.class.getClassLoader());
            this.classBytes.putAll(classBytes);
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] buf = classBytes.get(name);
            if (buf == null) {
                return super.findClass(name);
            }
            classBytes.remove(name);
            return defineClass(name, buf, 0, buf.length);
        }
    }
}

通過DynamicLoader的compile方法可以把純字串的str轉成byte[]陣列,有了byte[]陣列就可以很方便的獲取到class物件了,自定義一個MemoryClassLoader通過defineClass方法來獲取到class物件。這樣基本所有的事情都做完了。下面我們寫一個工廠類來獲取代理類。

package meituan.zylproxy.util;

import java.util.Map;

import meituan.zylproxy.DynamicLoader;
import meituan.zylproxy.handlder.ZYLInvocationHandler;

public class PorxyFactory {

    
    //單interface的時候用
    public static Object newProxyInstance(Class<?> c,ZYLInvocationHandler h) throws Exception{

        String classStr = ClassUtil.mackProxyClass(c);
        Map<String, byte[]> m = DynamicLoader.compile(classStr);
        DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m);
        Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]);
        return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h);
    }

    //多interface的時候用
    public static Object newProxyInstancewWithMultiClass(Class<?>[] c,ZYLInvocationHandler h) throws Exception{

        String classStr = ClassUtil.mackMultiProxyClass(c);
        System.out.println (classStr);
        Map<String, byte[]> m = DynamicLoader.compile(classStr);
        DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m);
        Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]);
        return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h);
    }
}

 

最後一步我們測試一下結果吧,寫一個測試類

package meituan.zylproxy.test;

import meituan.zylproxy.handlder.Hander;
import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.impl.DtoImpl;
import meituan.zylproxy.util.PorxyFactory;

public class ZylPorxyTest {

     public static void main(String[] args) throws Exception {

         Idto d = (Idto) PorxyFactory.newProxyInstancewWithMultiClass(DtoImpl.class.getInterfaces(), new Hander(new DtoImpl()));
         d.add();
    }
}

很簡單,第一個引數是所有的介面,第二個是handler實現。最後我們看看結果。

 

大功告成。

有更多的更多的原始碼交流,請加群825199617交流,spring原始碼,spring mvc原始碼,手寫企業級高可用rpc框架等等更多精彩原始碼,等你來。