精盡 Dubbo 源碼分析 —— 動態代理(一)之 Javassist

1.概述

在 《Dubbo 用戶指南 —— schema 配置參考手冊》 中,我們可以看到 <dubbo:service /> 和 <dubbo:reference /> 標籤中,可以通過 “proxy” 屬性,可以配置動態代理的生成方式:
生成動態代理方式,可選:jdk / javassist

2.整體流程

在這裏插入圖片描述
在 Consumer 中,我們調用 Service 接口的方法時,實際調用的是 Dubbo 動態代理。下面先一起來看一個生成的 proxy 代碼的示例:

package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.demo.DemoService;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class proxy0
implements ClassGenerator.DC, EchoService, DemoService
 {
 public static Method[] methods;
 private InvocationHandler handler;
 public void bye(Object paramObject)
  {
  Object[] arrayOfObject = new Object[1];
   arrayOfObject[0] = paramObject;
   Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
   }
 public String sayHello(String paramString)
 {
  Object[] arrayOfObject = new Object[1];
 arrayOfObject[0] = paramString;
 Object localObject = this.handler.invoke(this, methods[1], arrayOfObject);
  return (String)localObject;
 }
  public Object $echo(Object paramObject)
{
   Object[] arrayOfObject = new Object[1];
  arrayOfObject[0] = paramObject;
Object localObject = this.handler.invoke(this, methods[2], arrayOfObject);
  return (Object)localObject;
   } 
 public proxy0() {}
 public proxy0(InvocationHandler paramInvocationHandler) {
   this.handler = paramInvocationHandler;
 }
}

注:生成的 proxy 類會實現我們定義的 Service 接口( 例如,此處是 DemoService )

在 Provider 中,XXXProtocol 會獲得被調用的 Exporter 對象,從而獲得到 Invoker 對象。但是呢,Invoker 對象實際和 Service 實現對象,是無法直接調用,需要有中間的一層 Wrapper 來代理分發到 Service 對應的方法。下面我們來看一個生成的 Wrapper 代碼的示例:

package com.alibaba.dubbo.common.bytecode;  
import com.alibaba.dubbo.demo.provider.DemoDAO;
 import com.alibaba.dubbo.demo.provider.DemoServiceImpl; 
 import java.lang.reflect.InvocationTargetException; 
 import java.util.Map; 
 public class Wrapper1   extends Wrapper implements ClassGenerator.DC
 {
   public static String[] pns;
   public static Map pts;
   public static String[] mns;
   public static String[] dmns;
   public static Class[] mts0;
   public static Class[] mts1;
   public static Class[] mts2;
   
   public String[] getPropertyNames()
   {
     return pns;
   }
   
   public boolean hasProperty(String paramString)
   {
     return pts.containsKey(paramString);
   }
   
   public Class getPropertyType(String paramString)
   {
     return (Class)pts.get(paramString);
   }
   
   public String[] getMethodNames()
   {
     return mns;
   }
   
   public String[] getDeclaredMethodNames()
   {
     return dmns;
   }
   
   public void setPropertyValue(Object paramObject1, String paramString, Object paramObject2)
   {
     DemoServiceImpl w;
     try
     {
       w = (DemoServiceImpl)paramObject1;
     }
     catch (Throwable localThrowable)
     {
       throw new IllegalArgumentException(localThrowable);
     }
     if (paramString.equals("test01"))
     {
       w.test01 = ((String)paramObject2);
       return;
     }
     if (paramString.equals("demoDAO"))
     {
       localDemoServiceImpl.setDemoDAO((DemoDAO)paramObject2);
       return;
     }
     throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
   }
   
   public Object getPropertyValue(Object paramObject, String paramString)
   {
     DemoServiceImpl w;
     try
     {
       w = (DemoServiceImpl)paramObject;
     }
     catch (Throwable localThrowable)
     {
       throw new IllegalArgumentException(localThrowable);
     }
     if (paramString.equals("test01")) {
       return localDemoServiceImpl.test01;
     }
     throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
   }
   
   public Object invokeMethod(Object paramObject, String paramString, Class[] paramArrayOfClass, Object[] paramArrayOfObject)
     throws InvocationTargetException
   {
     DemoServiceImpl w;
     try
     {
       w = (DemoServiceImpl)paramObject;
     }
     catch (Throwable localThrowable1)
     {
       throw new IllegalArgumentException(localThrowable1);
     }
     try
     {
       if ("sayHello".equals(paramString) && paramArrayOfClass.length == 1) {
         return w.sayHello((String)paramArrayOfObject[0]);
       }
       if ("bye".equals(paramString) && paramArrayOfClass.length == 1)
       {
         w.bye((Object)paramArrayOfObject[0]);
         return null;
       }
       if ("setDemoDAO".equals(paramString) && paramArrayOfClass.length == 1)
       {
         w.setDemoDAO((DemoDAO)paramArrayOfObject[0]);
         return null;
       }
     }
     catch (Throwable localThrowable2)
     {
       throw new InvocationTargetException(localThrowable2);
     }
     throw new NoSuchMethodException("Not found method \"" + paramString + "\" in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
   }

注:不同於生成的 proxy類,不實現 Service 接口類,而是在 #invokeMethod(paramObject, paramString, paramArrayOfClass, paramArrayOfObject) 方法,提供給 Invoker#invoke(invocation) 中調用,統一分發請求到 Service 對應的方法。從職能上來看,有一點像硬編碼的 Controller 。

3.ProxyFactory

在這裏插入圖片描述

3.1 AbstractProxyFactory

實現 ProxyFactory 接口,代理工廠抽象類。代碼如下:

/**
 * AbstractProxyFactory
 *
 * 代理工廠抽象類
 */
public abstract class AbstractProxyFactory implements ProxyFactory {

    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        Class<?>[] interfaces = null;
        // TODO 8022 芋艿
        String config = invoker.getUrl().getParameter("interfaces");
        if (config != null && config.length() > 0) {
            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                interfaces = new Class<?>[types.length + 2];
                interfaces[0] = invoker.getInterface();
                interfaces[1] = EchoService.class;
                for (int i = 0; i < types.length; i++) {
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
        // 增加 EchoService 接口,用於回生測試。參見文檔《回聲測試》https://dubbo.gitbooks.io/dubbo-user-book/demos/echo-service.html
        if (interfaces == null) {
            interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
        }
        return getProxy(invoker, interfaces);
    }

    public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);

3.2 JavassistProxyFactory

 * JavassistRpcProxyFactory
 *
 * 基於 Javassist 代理工廠實現類
 */
public class JavassistProxyFactory extends AbstractProxyFactory {

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        // TODO Wrapper類不能正確處理帶$的類名
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                Class<?>[] parameterTypes,
                Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

}

3.3 InvokerInvocationHandler

實現 java.lang.reflect.InvocationHandler 接口,代碼如下:

/**
 * InvokerHandler
 */
public class InvokerInvocationHandler implements InvocationHandler {

    /**
     * Invoker 對象
     */
    private final Invoker<?> invoker;

    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        // wait 等方法,直接反射調用
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        // 基礎方法,不使用 RPC 調用
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);
        }
        // RPC 調用
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }

}

4.AbstractProxyInvoker

實現 Invoker 接口,代理 Invoker 對象的抽象類。

4.1 屬性

 /**
     * 代理的對象,一般是 Service 實現對象
     */
    private final T proxy;
    /**
     * 接口類型,一般是 Service 接口
     */
    private final Class<T> type;
    /**
     * URL 對象,一般是暴露服務的 URL 對象
     */
    private final URL url;

    public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
        if (proxy == null) {
            throw new IllegalArgumentException("proxy == null");
        }
        if (type == null) {
            throw new IllegalArgumentException("interface == null");
        }
        if (!type.isInstance(proxy)) { //
            throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
        }
        this.proxy = proxy;
        this.type = type;
        this.url = url;
    }

4.2 屬性

public Result invoke(Invocation invocation) throws RpcException {
        try {
            return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
        } catch (InvocationTargetException e) {
            return new RpcResult(e.getTargetException());
        } catch (Throwable e) {
            throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

調用doInvoke抽象方法,執行調用,返回調用結果

    /**
     * 執行調用
     *
     * @param proxy 代理的對象
     * @param methodName 方法名
     * @param parameterTypes 方法參數類型數組
     * @param arguments 方法參數數組
     * @return 調用結果
     * @throws Throwable 發生異常
     */
    protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;

Wrapper 抽象類,用於創建某個對象的方法調用的包裝器,以避免反射調用,提高性能。即:

// 反射
Method#invoke(Object instance, Object[] args)

// 優化成===>

// Wrapper
Wrapper#invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)

5.1 getWrapper

/**
     * get wrapper.
     *
     * 根據指定類,獲得 Wrapper 對象
     *
     * @param c Class instance. 指定類
     * @return Wrapper instance(not null). Wrapper 對象
     */
    public static Wrapper getWrapper(Class<?> c) {
        // 判斷是否繼承 ClassGenerator.DC.class ,如果是,拿到父類,避免重複包裝
        while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
            c = c.getSuperclass();

        // 指定類爲 Object.class
        if (c == Object.class)
            return OBJECT_WRAPPER;

        // 從緩存中獲得 Wrapper 對象
        Wrapper ret = WRAPPER_MAP.get(c);
        // 創建 Wrapper 對象,並添加到緩存
        if (ret == null) {
            ret = makeWrapper(c);
            WRAPPER_MAP.put(c, ret);
        }
        return ret;
    }

5.2 makeWrapper

創建 Wrapper 對象。代碼如下:

    private static Wrapper makeWrapper(Class<?> c) {
        // 非私有類
        if (c.isPrimitive())
            throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

        // 類名
        String name = c.getName();
        // 類加載器
        ClassLoader cl = ClassHelper.getClassLoader(c);

        // 設置屬性方法 `#setPropertyValue(o, n, v)` 的開頭的代碼
        StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
        // 獲得屬性方法 `#getPropertyValue(o, n)` 的開頭的代碼
        StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
        // 調用方法 `#invokeMethod(o, n, p, v)` 的開頭的代碼
        StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

        // 添加每個方法的,被調用對象的類型轉換的代碼
        c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
        c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
        c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");

        // 屬性名與屬性名的集合,用於 `#hasProperty(...)` `#setPropertyValue(...)` `getPropertyValue(...)` 方法。
        Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
        // 方法簽名與方法對象的集合,用於 `#invokeMethod(..)` 方法。
        Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
        // 方法名數組用於 `#getMethodNames()` 方法。
        List<String> mns = new ArrayList<String>(); // method names.
        // 定義的方法名數組,用於 `#getDeclaredMethodNames()` 方法。
        List<String> dmns = new ArrayList<String>(); // declaring method names.

        // 循環 public 屬性,添加每個屬性的設置和獲得分別到 `#setPropertyValue(o, n, v)` 和 `#getPropertyValue(o, n)` 的代碼
        // get all public field.
        for (Field f : c.getFields()) {
            String fn = f.getName();
            Class<?> ft = f.getType();
            if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) // 排除 static 和 transient
                continue;

            c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
            c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
            // 添加到 `pts` 中
            pts.put(fn, ft);
        }

        Method[] methods = c.getMethods();
        // 如果有方法,添加 `#invokeMethod(o, n, p, v)` 的 try 的代碼
        // get all public method.
        boolean hasMethod = hasMethods(methods);
        if (hasMethod) {
            c3.append(" try{");
        }
        for (Method m : methods) {
            // 跳過來自 Object 的內置方法
            if (m.getDeclaringClass() == Object.class) //ignore Object's method.
                continue;

            String mn = m.getName(); // 方法名
            // 使用方法名 + 方法參數長度來判斷
            c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
            int len = m.getParameterTypes().length;
            c3.append(" && ").append(" $3.length == ").append(len);

            // 若相同方法名存在多個,增加參數類型數組的比較判斷
            boolean override = false;
            for (Method m2 : methods) {
                if (m != m2 && m.getName().equals(m2.getName())) {
                    override = true;
                    break;
                }
            }
            if (override) {
                if (len > 0) {
                    for (int l = 0; l < len; l++) {
                        c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
                                .append(m.getParameterTypes()[l].getName()).append("\")");
                    }
                }
            }

            c3.append(" ) { ");

            // 添加調用對象的對應方法的代碼
            if (m.getReturnType() == Void.TYPE)
                c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
            else
                c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");

            c3.append(" }");

            // 添加到 `mns` 中
            mns.add(mn);
            // 添加到 `dmns` 中
            if (m.getDeclaringClass() == c)
                dmns.add(mn);
            // 添加到 `ms` 中
            ms.put(ReflectUtils.getDesc(m), m);
        }
        // 如果有方法,添加 `#invokeMethod(o, n, p, v)` 的 catch 的代碼
        if (hasMethod) {
            c3.append(" } catch(Throwable e) { ");
            c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
            c3.append(" }");
        }
        // 添加 `#invokeMethod(o, n, p, v)` 的未匹配到方法的代碼
        c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");

        // 循環 setting/getting 方法,添加每個屬性的設置和獲得分別到 `#setPropertyValue(o, n, v)` 和 `#getPropertyValue(o, n)` 的代碼
        // deal with get/set method.
        Matcher matcher;
        for (Map.Entry<String, Method> entry : ms.entrySet()) {
            String md = entry.getKey();
            Method method = entry.getValue();
            if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                String pn = propertyName(matcher.group(1));
                c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
                // 添加到 `pts` 中
                pts.put(pn, method.getReturnType());
            } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                String pn = propertyName(matcher.group(1));
                c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
                // 添加到 `pts` 中
                pts.put(pn, method.getReturnType());
            } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) { // 不支持 public T setName(String name) { this.name = name; return this;} 這種返回 this 的形式。
                Class<?> pt = method.getParameterTypes()[0];
                String pn = propertyName(matcher.group(1));
                c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
                // 添加到 `pts` 中
                pts.put(pn, pt);
            }
        }
        c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
        c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");

        // make class
        long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
        // 創建 ClassGenerator 對象
        ClassGenerator cc = ClassGenerator.newInstance(cl);
        // 設置類名
        cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
        // 設置父類爲 Wrapper.class
        cc.setSuperClass(Wrapper.class);

        // 添加構造方法,參數 空
        cc.addDefaultConstructor();
        // 添加靜態屬性 `pns` 的代碼
        cc.addField("public static String[] pns;"); // property name array.
        // 添加靜態屬性 `pts` 的代碼
        cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
        // 添加靜態屬性 `pts` 的代碼
        cc.addField("public static String[] mns;"); // all method name array.
        // 添加靜態屬性 `dmns` 的代碼
        cc.addField("public static String[] dmns;"); // declared method name array.
        // 添加靜態屬性 `mts` 的代碼。每個方法的參數數組。
        for (int i = 0, len = ms.size(); i < len; i++)
            cc.addField("public static Class[] mts" + i + ";");

        // ======= 添加抽象方法的實現,到 `cc` 中
        // 添加 `#getPropertyNames()` 的代碼到 `cc`
        cc.addMethod("public String[] getPropertyNames(){ return pns; }");
        // 添加 `#hasProperty(n)` 的代碼到 `cc`
        cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
        // 添加 `#getPropertyType(n)` 的代碼到 `cc`
        cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
        // 添加 `#getMethodNames()` 的代碼到 `cc`
        cc.addMethod("public String[] getMethodNames(){ return mns; }");
        // 添加 `#getDeclaredMethodNames()` 的代碼到 `cc`
        cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
        // 添加 `#setPropertyValue(o, n, v)` 的代碼到 `cc`
        cc.addMethod(c1.toString());
        // 添加 `#getPropertyValue(o, n)` 的代碼到 `cc`
        cc.addMethod(c2.toString());
        // 添加 `#invokeMethod(o, n, p, v)` 的代碼到 `cc`
        cc.addMethod(c3.toString());

        try {
            // 生成類
            Class<?> wc = cc.toClass();
            // 反射,設置靜態變量的值
            // setup static field.
            wc.getField("pts").set(null, pts);
            wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
            wc.getField("mns").set(null, mns.toArray(new String[0]));
            wc.getField("dmns").set(null, dmns.toArray(new String[0]));
            int ix = 0;
            for (Method m : ms.values())
                wc.getField("mts" + ix++).set(null, m.getParameterTypes());
            // 創建對象
            return (Wrapper) wc.newInstance();
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            // 釋放資源
            cc.release();
            ms.clear();
            mns.clear();
            dmns.clear();
        }
    }

6. Proxy

代理抽象類,用於創建 Proxy 和 proxy 對象。

6.1 getProxy

獲取Proxy

  /**
     * Get proxy.
     *
     * @param ics interface class array.
     * @return Proxy instance.
     */
    public static Proxy getProxy(Class<?>... ics) {
        return getProxy(ClassHelper.getClassLoader(Proxy.class), ics);
    }

6.2 getProxy

/**
     * Get proxy.
     *
     * @param cl  class loader.
     * @param ics interface class array.
     * @return Proxy instance.
     */
    public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
        // 校驗接口超過上限
        if (ics.length > 65535)
            throw new IllegalArgumentException("interface limit exceeded");

        // use interface class name list as key.
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < ics.length; i++) {
            String itf = ics[i].getName();
            // 校驗是否爲接口
            if (!ics[i].isInterface())
                throw new RuntimeException(itf + " is not a interface.");

            // 加載接口類
            Class<?> tmp = null;
            try {
                tmp = Class.forName(itf, false, cl);
            } catch (ClassNotFoundException e) {
            }

            if (tmp != ics[i]) // 加載接口類失敗
                throw new IllegalArgumentException(ics[i] + " is not visible from class loader");

            sb.append(itf).append(';');
        }

        // use interface class name list as key.
        String key = sb.toString();

        // get cache by class loader.
        Map<String, Object> cache;
        synchronized (ProxyCacheMap) {
            cache = ProxyCacheMap.get(cl);
            if (cache == null) {
                cache = new HashMap<String, Object>();
                ProxyCacheMap.put(cl, cache);
            }
        }

        // 獲得 Proxy
        Proxy proxy = null;
        synchronized (cache) {
            do {
                // 從緩存中獲取 Proxy
                Object value = cache.get(key);
                if (value instanceof Reference<?>) {
                    proxy = (Proxy) ((Reference<?>) value).get();
                    if (proxy != null)
                        return proxy;
                }
                // 緩存中不存在,設置生成 Proxy 代碼標記。創建中時,其他創建請求等待,避免併發。
                if (value == PendingGenerationMarker) {
                    try {
                        cache.wait();
                    } catch (InterruptedException e) {
                    }
                } else {
                    cache.put(key, PendingGenerationMarker);
                    break;
                }
            }
            while (true);
        }

        long id = PROXY_CLASS_COUNTER.getAndIncrement();
        String pkg = null;
        ClassGenerator ccp = null, // proxy class generator
                ccm = null; // Proxy class generator
        try {
            // 創建 proxy 代碼生成器
            ccp = ClassGenerator.newInstance(cl);

            Set<String> worked = new HashSet<String>(); // 已處理方法簽名集合。key:方法簽名
            List<Method> methods = new ArrayList<Method>(); // 已處理方法集合。

            // 處理接口
            for (int i = 0; i < ics.length; i++) {
                // 非 public 接口,使用接口包名
                if (!Modifier.isPublic(ics[i].getModifiers())) {
                    String npkg = ics[i].getPackage().getName();
                    if (pkg == null) {
                        pkg = npkg;
                    } else {
                        if (!pkg.equals(npkg)) // 實現了兩個非 public 的接口,
                            throw new IllegalArgumentException("non-public interfaces from different packages");
                    }
                }
                // 添加接口
                ccp.addInterface(ics[i]);

                // 處理接口方法
                for (Method method : ics[i].getMethods()) {
                    // 添加方法簽名到已處理方法簽名集合
                    String desc = ReflectUtils.getDesc(method);
                    if (worked.contains(desc))
                        continue;
                    worked.add(desc);

                    // 生成接口方法實現代碼
                    int ix = methods.size();
                    Class<?> rt = method.getReturnType();
                    Class<?>[] pts = method.getParameterTypes();

                    StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
                    for (int j = 0; j < pts.length; j++)
                        code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
                    code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
                    if (!Void.TYPE.equals(rt))
                        code.append(" return ").append(asArgument(rt, "ret")).append(";");

                    methods.add(method);
                    // 添加方法
                    ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
                }
            }

            // 設置包路徑
            if (pkg == null)
                pkg = PACKAGE_NAME;

            // ===== 設置 proxy 代碼生成的屬性 =====
            // create ProxyInstance class.
            // 設置類名
            String pcn = pkg + ".proxy" + id;
            ccp.setClassName(pcn);
            // 添加靜態屬性 methods
            ccp.addField("public static java.lang.reflect.Method[] methods;");
            // 添加屬性 handler
            ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
            // 添加構造方法,參數 handler
            ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
            // 添加構造方法,參數 空
            ccp.addDefaultConstructor();
            // 生成類
            Class<?> clazz = ccp.toClass();
            // 設置靜態屬性 methods
            clazz.getField("methods").set(null, methods.toArray(new Method[0]));

            // create Proxy class.
            // 創建 Proxy 代碼生成器
            String fcn = Proxy.class.getName() + id;
            ccm = ClassGenerator.newInstance(cl);
            // 設置類名
            ccm.setClassName(fcn);
            // 添加構造方法,參數 空
            ccm.addDefaultConstructor();
            // 設置父類爲 Proxy.class
            ccm.setSuperClass(Proxy.class);
            // 添加方法 #newInstance(handler)
            ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
            // 生成類
            Class<?> pc = ccm.toClass();
            // 創建 Proxy 對象
            proxy = (Proxy) pc.newInstance();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            // release ClassGenerator
            if (ccp != null)
                ccp.release();
            if (ccm != null)
                ccm.release();
            // 喚醒緩存 wait
            synchronized (cache) {
                if (proxy == null)
                    cache.remove(key);
                else
                    cache.put(key, new WeakReference<Proxy>(proxy));
                cache.notifyAll();
            }
        }
        return proxy;
    }

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