溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何寫java代理

發(fā)布時(shí)間:2021-10-19 15:10:24 來(lái)源:億速云 閱讀:126 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“如何寫java代理”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一:常用的java代理模式

        一般經(jīng)常做java開(kāi)發(fā)的知道java的代理模式一共有三種,第一種也就是靜態(tài)代理,這種用法比較簡(jiǎn)單,沒(méi)有什么魔法棒,比較好理解,另外兩種分別是JDK代理和cglib代理,他們分別是對(duì)接口代理和對(duì)class類本身進(jìn)行代理,jdk代理要求類必須實(shí)現(xiàn)有一個(gè)或者多個(gè)接口,對(duì)接口進(jìn)行字節(jié)碼增強(qiáng)在內(nèi)存中實(shí)現(xiàn)新的class類去反射調(diào)用用戶target的實(shí)現(xiàn)類,這里需要說(shuō)明的是不管是cglic代理也好還是jdk代理他們?cè)趦?nèi)存中都要占據(jù)方法區(qū)資源(jdk8 叫原空間),從而達(dá)到代理目的,而cglib代理是對(duì)class類本身進(jìn)行字節(jié)碼增強(qiáng)配合fastclass來(lái)實(shí)現(xiàn)代理,關(guān)于更多的cglib和jdk代理相關(guān)的內(nèi)容大家可以google搜索一下,網(wǎng)上有很多這里不做再多的說(shuō)明。下面我們摒棄jdk,和cglib的復(fù)雜源碼來(lái)自己實(shí)現(xiàn)一個(gè)代理模式,來(lái)更深刻的了解一下代理究竟是怎么形成的。

二:java原生jdk代理demo和源碼分析

       代理模式是指給某一個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制對(duì)原對(duì)象的引用。通俗的來(lái)講代理模式就是我們生活中常見(jiàn)的中介。這種模式有什么用呢?它可以在原對(duì)象的基礎(chǔ)上增強(qiáng)原對(duì)象的功能,比如在原對(duì)象調(diào)用一個(gè)方法的前后進(jìn)行日志、事務(wù)操作等。Spring AOP就使用了代理模式。如何實(shí)現(xiàn)代理模式呢?首先來(lái)看靜態(tài)代理。靜態(tài)代理是指在程序運(yùn)行前就已經(jīng)存在的編譯好的代理類是為靜態(tài)代理。實(shí)現(xiàn)靜態(tài)代理有四個(gè)步驟:

     ①定義業(yè)務(wù)接口;  
     ②被代理類實(shí)現(xiàn)業(yè)務(wù)接口;  
     ③定義代理類并實(shí)現(xiàn)業(yè)務(wù)接口;  
     ④最后便可通過(guò)客戶端進(jìn)行調(diào)用。(這里可以理解成程序的main方法里的內(nèi)容)  
     我們按照這個(gè)步驟去實(shí)現(xiàn)靜態(tài)代理。需求:在向數(shù)據(jù)庫(kù)添加一個(gè)用戶時(shí)前后打印日志。

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("數(shù)據(jù)庫(kù)中插入:  "+name+" 的用戶");
    }

}

MyInvocationHandler.java

public class MyInvocationHandler implements InvocationHandler {
    //被代理對(duì)象,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("準(zhǔn)備向數(shù)據(jù)庫(kù)中插入數(shù)據(jù)");
        Object returnvalue = method.invoke(target, args);
        System.out.println("插入數(shù)據(jù)庫(kù)成功");

        return returnvalue;
    }
}

測(cè)試類

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("張玉龍");
    }

  使用上非常簡(jiǎn)單、網(wǎng)上demo也很多,不做充分講解,對(duì)jdk代理用法的小伙伴如果還不熟悉這塊代碼,就先了解一下jdk代理的使用方式,然后在回來(lái)繼續(xù)看下面的源碼分析


JDK代理源碼深度分析

這部分如果想要更快更好的理解,建議一邊對(duì)著源碼(本文JDK 1.8),一邊看著博客。畢竟自己親身實(shí)踐效果才好嘛。 Proxy.newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h) 產(chǎn)生了代理對(duì)象,所以我們進(jìn)到 newProxyInstance 的實(shí)現(xiàn):

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

這段代碼核心就是通過(guò) getProxyClass0(loader, intfs)得到代理類的Class對(duì)象,然后通過(guò)Class對(duì)象得到構(gòu)造方法,進(jìn)而創(chuàng)建代理對(duì)象。下一步看 getProxyClass0這個(gè)方法。

//此方法也是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定義了,并實(shí)現(xiàn)了給定的接口interfaces,
        //那么就返回緩存的代理類對(duì)象,否則使用ProxyClassFactory創(chuàng)建代理類。
        return proxyClassCache.get(loader, interfaces);
    }

 這里看到proxyClassCache,有Cache便知道是緩存的意思,正好呼應(yīng)了前面Look up or generate the designated proxy class。查詢(在緩存中已經(jīng)有)或生成指定的代理類的class對(duì)象這段注釋。

proxyClassCache是個(gè)WeakCache類的對(duì)象,調(diào)用proxyClassCache.get(loader, interfaces); 可以得到緩存的代理類或創(chuàng)建代理類(沒(méi)有緩存的情況)。說(shuō)明WeakCache中有  get這個(gè)方法。先看下WeakCache類的定義(這里先只給出變量的定義和構(gòu)造函數(shù)):

//K代表key的類型,P代表參數(shù)的類型,V代表value的類型。
// WeakCache<ClassLoader, Class<?>[], Class<?>>  proxyClassCache  說(shuō)明proxyClassCache存的值是Class<?>對(duì)象,正是我們需要的代理類對(duì)象。
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變量是實(shí)現(xiàn)緩存的核心變量,他是一個(gè)雙重的Map結(jié)構(gòu):           (key, sub-key) -> value。其中key是傳進(jìn)來(lái)的Classloader進(jìn)行包裝后的對(duì)象,sub-key是由WeakCache構(gòu)造函數(shù)傳人的     KeyFactory()生成的。value就是產(chǎn)生代理類的對(duì)象,是由WeakCache構(gòu)造函數(shù)傳人的     ProxyClassFactory()生成的


 好,大體上說(shuō)完WeakCache這個(gè)類的作用,我們回到剛才 proxyClassCache.get(loader, interfaces);這句代碼。get是WeakCache里的方法。源碼如下

//K和P就是WeakCache定義中的泛型,key是類加載器,parameter是接口類數(shù)組
public V get(K key, P parameter) {
        //檢查parameter不為空
        Objects.requireNonNull(parameter);
         //清除無(wú)效的緩存
        expungeStaleEntries();
        // cacheKey就是(key, sub-key) -> value里的一級(jí)key,
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //根據(jù)一級(jí)key得到 ConcurrentMap<Object, Supplier<V>>對(duì)象。如果之前不存在,則新建一個(gè)ConcurrentMap<Object, Supplier<V>>和cacheKey(一級(jí)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
        //這部分就是調(diào)用生成sub-key的代碼,上面我們已經(jīng)看過(guò)怎么生成的了
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //通過(guò)sub-key得到supplier
        Supplier<V> supplier = valuesMap.get(subKey);
        //supplier實(shí)際上就是這個(gè)factory
        Factory factory = null;

        while (true) {
            //如果緩存里有supplier ,那就直接通過(guò)get方法,得到代理類對(duì)象,返回,就結(jié)束了,一會(huì)兒分析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
            //下面的所有代碼目的就是:如果緩存中沒(méi)有supplier,則創(chuàng)建一個(gè)Factory對(duì)象,把factory對(duì)象在多線程的環(huán)境下安全的賦給supplier。
            //因?yàn)槭窃趙hile(true)中,賦值成功后又回到上面去調(diào)get方法,返回才結(jié)束。
            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);
                }
            }
        }
    }

  所以接下來(lái)我們看Factory類中的get方法。

public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            //重新檢查得到的supplier是不是當(dāng)前對(duì)象
            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 {
                 //代理類就是在這個(gè)位置調(diào)用valueFactory生成的
                 //valueFactory就是我們傳入的 new ProxyClassFactory()
                //一會(huì)我們分析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是用來(lái)實(shí)現(xiàn)緩存的有效性
            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;
        }
    }

  撥云見(jiàn)日,來(lái)到ProxyClassFactory的apply方法,代理類就是在這里生成的。

//這里的BiFunction<T, U, R>是個(gè)函數(shù)式接口,可以理解為用T,U兩種類型做參數(shù),得到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
        //用于生成代理類名字的計(jì)數(shù)器
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
              
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            //驗(yàn)證代理接口,可不看
            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
            //代理類訪問(wèn)控制符: 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.
             */
            //驗(yàn)證所有非公共的接口在同一個(gè)包內(nèi);公共的就無(wú)需處理
            //生成包名和類名的邏輯,包名默認(rèn)是com.sun.proxy,類名默認(rèn)是$Proxy 加上一個(gè)自增的整數(shù)值
            //如果被代理類是 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.
             */
            //核心部分,生成代理類的字節(jié)碼
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //把代理類加載到JVM中,至此動(dòng)態(tài)代理過(guò)程基本結(jié)束了
                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());
            }
        }
    }

  到這里其實(shí)已經(jīng)分析完了,但是本著深究的態(tài)度,決定看看JDK生成的動(dòng)態(tài)代理字節(jié)碼是什么,于是我們將字節(jié)碼保存到磁盤上的class文件中。代碼如下:

public static void main(String[] args) {

        IUserService target = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(target);
        //第一個(gè)參數(shù)是指定代理類的類加載器(我們傳入當(dāng)前測(cè)試類的類加載器)
        //第二個(gè)參數(shù)是代理類需要實(shí)現(xiàn)的接口(我們傳入被代理類實(shí)現(xiàn)的接口,這樣生成的代理類和被代理類就實(shí)現(xiàn)了相同的接口)
        //第三個(gè)參數(shù)是invocation handler,用來(lái)處理方法的調(diào)用。這里傳入我們自己實(shí)現(xiàn)的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();
            }
        }
        
    }

   運(yùn)行這段代碼,會(huì)在D盤生成一個(gè)名為$Proxy0.class的文件。通過(guò)反編譯工具,得到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;
    //代理類的構(gòu)造函數(shù),其參數(shù)正是是InvocationHandler實(shí)例,
    //Proxy.newInstance方法就是通過(guò)通過(guò)這個(gè)構(gòu)造函數(shù)來(lái)創(chuàng)建代理實(shí)例的
    public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }
     // Object類中的三個(gè)方法,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方法在這里被調(diào)用
            super.h.invoke(this, m3, new Object[] {
                s
            });
            return;
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            // 在這里調(diào)用了invoke方法。
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch (Error ) { }
        catch (Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    
    // 靜態(tài)代碼塊對(duì)變量進(jìn)行一些初始化工作
    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類的三個(gè)方法:toString,hashCode,equals。還有我們需要被代理的方法。

JDK代理類的cache clear機(jī)制

大家都知道、在項(xiàng)目中被代理的class越來(lái)越多,所以jdk會(huì)搞一個(gè)cache的方式來(lái)防止相同的代理接口重復(fù)生成class,影響性能不說(shuō),實(shí)現(xiàn)也不是很優(yōu)雅,那么現(xiàn)在就會(huì)有一個(gè)問(wèn)題了,當(dāng)classloader已經(jīng)在內(nèi)存中沒(méi)有依賴的時(shí)候,被代理的proxy class其實(shí)也沒(méi)有什么意義了,這樣就需要清空無(wú)用的cache,java Proxy采用了非常巧妙的“弱引用機(jī)制”,我們來(lái)看下面的代碼

我們還是繼續(xù)看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;
            }
        }
.......
}

其中源碼中有一個(gè)方法expungeStaleEntries、我們進(jìn)去這個(gè)方法一窺究竟

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

  代碼很清晰了,清空被代理的對(duì)象。現(xiàn)在的關(guān)鍵就是refQueue對(duì)象是怎么來(lái)的。我們繼續(xù)找一下跟refQueue相關(guān)的源碼、在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
        }
.....
}

 這樣看就非常清晰了、原來(lái)是CacheKey繼承了WeakReference弱引用機(jī)制,當(dāng)弱引用依賴的key沒(méi)有引用的時(shí)候,當(dāng)前失效的對(duì)象就會(huì)進(jìn)入ReferenceQueue中來(lái)實(shí)現(xiàn)清空cache的功能、這種實(shí)現(xiàn)思路和ThreadLocal的實(shí)現(xiàn)原理是一樣的、大家有興趣可以去閱讀以下相關(guān)源碼。

三:手把手寫基于接口的java代理

上面我們分析了jdk動(dòng)態(tài)代理源碼、那我們是不是可以自己用自己的方式去寫一個(gè)屬于自己的jdk代理呢,答案是可以的

首先我們寫一個(gè)基類,當(dāng)然我并沒(méi)有在基類里面寫什么東西,只是模擬java中的proxy類而已,當(dāng)然我們也可以豐富的去拓展一下這個(gè)類的方法,來(lái)實(shí)現(xiàn)更多的功能,讀者可以通過(guò)讀完這篇文章之后自己去考慮一下如何來(lái)拓展。

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

代理的核心接口,我們?nèi)プ龃淼臅r(shí)候一定是通過(guò)反射去調(diào)用的,不管jdk也好還是cglib也好,永遠(yuǎn)也無(wú)法脫離反射,我們照貓畫虎,自己寫一個(gè)代理接口核心類,這并不是什么難題,看起來(lái)和jdk的核心類接口也沒(méi)有什么區(qū)別。

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 }

說(shuō)明一下 第一個(gè)參數(shù)proxy是代表代理類,而不是用戶自己寫的原生類實(shí)現(xiàn)。參數(shù)Method是接口的方法,args是運(yùn)行時(shí)參數(shù)列表,在運(yùn)行時(shí)傳遞過(guò)來(lái)的實(shí)際上就是實(shí)現(xiàn)類的參數(shù),好了,下面讓我們?nèi)ド钊牒诵摹?/p>

我們自定義兩個(gè)接口和接口的實(shí)現(xiàn)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{

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

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

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

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

}

這是幾個(gè)再簡(jiǎn)單不過(guò)的接口和實(shí)現(xiàn)類了,也沒(méi)有什么可說(shuō)的。接下來(lái)我們想對(duì)接口進(jìn)行代理,無(wú)非是我們動(dòng)態(tài)將接口進(jìn)行實(shí)現(xiàn),從而達(dá)到對(duì)使用者進(jìn)行自定義handle接口暴露而已,下面看一下我們需要生成一個(gè)什么樣的代理類。

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

這個(gè)類不是由用戶寫的,而是我們動(dòng)態(tài)生成的,對(duì)于jdk來(lái)說(shuō)是生成了字節(jié)碼,對(duì)cglib來(lái)說(shuō)是通過(guò)字節(jié)碼增強(qiáng),其實(shí)實(shí)現(xiàn)的方式有多種,后面為了更方便大家理解我用字符串的形式來(lái)動(dòng)態(tài)生成這么一個(gè)"家伙",先看看這個(gè)類干了些什么吧,也很簡(jiǎn)單。

public class IdtoPorxy extends ZylProxy implements Idto, Idto2

首先是繼承了剛才我們所說(shuō)的ZylProxy,留著今后拓展,可以參照java的Proxy,然后并且動(dòng)態(tài)的實(shí)現(xiàn)了這兩個(gè)接口。很簡(jiǎn)單

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

這個(gè)是通過(guò)構(gòu)造函數(shù)傳進(jìn)來(lái)一個(gè)handler對(duì)象,對(duì)實(shí)現(xiàn)類的操作都靠它了。

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) {
        }
    }

枚舉出來(lái)所有的接口的方法,通過(guò)class.forname來(lái)獲取到Method元數(shù)據(jù)。備用

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

上面是要枚舉出來(lái)所有的方法的實(shí)現(xiàn),很簡(jiǎn)單都一個(gè)模樣,把實(shí)現(xiàn)交給handler去做就可以了。至于怎么實(shí)現(xiàn)靠handler,我們動(dòng)態(tài)生成的這個(gè)類只負(fù)責(zé)委托,不做任何事情??吹竭@里大家一定急不可待的想知道這個(gè)類怎么生成的了,我把我寫的源碼給大家貼出來(lái)看一下。

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

看起來(lái)很復(fù)雜,仔細(xì)看一下就看了那么幾個(gè)事情,把一個(gè)接口class或者多個(gè)接口class變成純字符串的過(guò)程,一共兩個(gè)方法,一個(gè)是單接口的實(shí)現(xiàn),很早之前寫的,第二個(gè)方法是多接口的實(shí)現(xiàn)支持多接口,只需要傳一個(gè)class對(duì)象就會(huì)生成代理類的字符串,這里僅僅是字符串,需要編譯成class使用。那么如何編譯成class呢。通過(guò)java中的工具類 JavaCompiler很簡(jiǎn)單的就可以生成了。我們來(lái)看兩個(gè)工具類實(shí)現(xiàn)

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

        @Overrideprotected 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);
        }
    }
}

通過(guò)DynamicLoader的compile方法可以把純字符串的str轉(zhuǎn)成byte[]數(shù)組,有了byte[]數(shù)組就可以很方便的獲取到class對(duì)象了,自定義一個(gè)MemoryClassLoader通過(guò)defineClass方法來(lái)獲取到class對(duì)象。這樣基本所有的事情都做完了。下面我們寫一個(gè)工廠類來(lái)獲取代理類。

package meituan.zylproxy.util;import java.util.Map;import meituan.zylproxy.DynamicLoader;import meituan.zylproxy.handlder.ZYLInvocationHandler;public class PorxyFactory {    //單interface的時(shí)候用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的時(shí)候用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);
    }
}

最后一步我們測(cè)試一下結(jié)果吧,寫一個(gè)測(cè)試類

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();
    }
}

很簡(jiǎn)單,第一個(gè)參數(shù)是所有的接口,第二個(gè)是handler實(shí)現(xiàn)。最后我們看看結(jié)果。

如何寫java代理

“如何寫java代理”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI