1. 程式人生 > 程式設計 >Dubbo原始碼解析(二十三)遠端呼叫——Proxy

Dubbo原始碼解析(二十三)遠端呼叫——Proxy

遠端呼叫——Proxy

目標:介紹遠端呼叫代理的設計和實現,介紹dubbo-rpc-api中的各種proxy包的原始碼。

前言

首先宣告叫做代理,代理在很多領域都存在,最形象的就是現在朋友圈的代理,廠家委託代理幫他們賣東西。這樣做廠家對於消費者來說就是透明的,並且代理可以自己加上一些活動或者銷售措施,但這並不影響到廠家。這裡的廠家就是委託類,而代理就可以抽象為代理類。這樣做有兩個優點,第一是可以隱藏代理類的實現,第二就是委託類和呼叫方的解耦,並且能夠在不修改委託類原本的邏輯情況下新增一些額外的處理。

代理分為兩種,靜態代理和動態代理。

  1. 靜態代理:如果代理類在程式執行前就已經存在,那麼這種代理就是靜態代理。
  2. 動態代理:代理類在程式執行時建立的代理方式。動態代理關係由兩組靜態代理關係組成,這就是動態代理的原理。

上述稍微回顧了一下靜態代理和動態代理,那麼dubbo對於動態代理有兩種方法實現,分別是javassist和jdk。Proxy 層封裝了所有介面的透明化代理,而在其它層都以 Invoker 為中心,只有到了暴露給使用者使用時,才用 Proxy 將 Invoker 轉成介面,或將介面實現轉成 Invoker,也就是去掉 Proxy 層 RPC 是可以 Run 的,只是不那麼透明,不那麼看起來像調本地服務一樣調遠端服務。我們來看看下面的圖:

dubbo-framework

我們能看到左邊是消費者的呼叫鏈,只有當消費者呼叫的時候,ProxyFactory才會通過Proxy把介面實現轉化為invoker,並且在其他層的呼叫都使用的是invoker,同樣的道理,在服務提供者暴露服務的時候,也只有在最後暴露給消費者的時候才會通過Proxy 將 Invoker 轉成介面。

動態代理的底層原理就是位元組碼技術,dubbo提供了兩種方式來實現代理:

  1. 第一種jdk,jdk動態代理比較簡單,它內建在JDK中,因此不依賴第三方jar包,但是功能相對較弱,當呼叫Proxy 的靜態方法建立動態代理類時,類名格式是“$ProxyN”,N代表第 N 次生成的動態代理類,如果重複建立動態代理類會直接返回原先建立的代理類。但是這個以“$ProxyN”命名的類是繼承Proxy類的,並且實現了其所代理的一組介面,這裡就出現了它的一個侷限性,由於java的類只能單繼承,所以JDK動態代理僅支援介面代理。
  2. 第二種是Javassist,Javassist是一款Java位元組碼引擎工具,能夠在執行時編譯生成class。該方法也是代理的預設方法。

原始碼分析

(一)AbstractProxyFactory

該類是代理工廠的抽象類,主要處理了一下需要代理的介面,然後把代理getProxy方法抽象出來。

public abstract class AbstractProxyFactory implements ProxyFactory {

    @Override
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        return getProxy(invoker,false);
    }

    @Override
    public <T> T getProxy(Invoker<T> invoker,boolean generic) throws RpcException {
        Class<?>[] interfaces = null;
        // 獲得需要代理的介面
        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];
                // 第一個放invoker的服務介面
                interfaces[0] = invoker.getInterface();
                // 第二個位置放回聲測試服務的介面類
                interfaces[1] = EchoService.class;
                // 其他介面迴圈放入
                for (int i = 0; i < types.length; i++) {
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
        // 如果介面為空,就是config為空,則是回聲測試
        if (interfaces == null) {
            interfaces = new Class<?>[]{invoker.getInterface(),EchoService.class};
        }

        // 如果是泛化服務,那麼在代理的介面集合中加入泛化服務型別
        if (!invoker.getInterface().equals(GenericService.class) && generic) {
            int len = interfaces.length;
            Class<?>[] temp = interfaces;
            interfaces = new Class<?>[len + 1];
            System.arraycopy(temp,0,interfaces,len);
            interfaces[len] = GenericService.class;
        }

        // 獲得代理
        return getProxy(invoker,interfaces);
    }

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

}
複製程式碼

邏輯比較簡單,就是處理了url中攜帶的interfaces的值。

(二)AbstractProxyInvoker

該類實現了Invoker介面,是代理invoker物件的抽象類。

@Override
public Result invoke(Invocation invocation) throws RpcException {
    try {
        // 呼叫了抽象方法doInvoke
        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);
    }
}

protected abstract Object doInvoke(T proxy,String methodName,Class<?>[] parameterTypes,Object[] arguments) throws Throwable;
複製程式碼

該類最關鍵的就是這兩個方法,一個是invoke方法,呼叫了抽象方法doInvoke,另一個則是抽象方法。該方法被子類實現。

(三)InvokerInvocationHandler

該類實現了InvocationHandler介面,動態代理類都必須要實現InvocationHandler介面,而該類實現的是對於基礎方法不適用rpc呼叫,其他方法使用rpc呼叫。

public class InvokerInvocationHandler implements InvocationHandler {

    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();
        // 如果方法引數型別是object型別,則直接反射呼叫
        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();
    }

}
複製程式碼

(四)StubProxyFactoryWrapper

該類實現了本地存根的邏輯,關於本地存根的概念和使用在官方檔案中都有詳細說明。

地址:dubbo.apache.org/zh-cn/docs/…

public class StubProxyFactoryWrapper implements ProxyFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(StubProxyFactoryWrapper.class);

    /**
     * 代理工廠
     */
    private final ProxyFactory proxyFactory;

    /**
     * 協議
     */
    private Protocol protocol;

    public StubProxyFactoryWrapper(ProxyFactory proxyFactory) {
        this.proxyFactory = proxyFactory;
    }

    public void setProtocol(Protocol protocol) {
        this.protocol = protocol;
    }

    @Override
    public <T> T getProxy(Invoker<T> invoker,boolean generic) throws RpcException {
        return proxyFactory.getProxy(invoker,generic);
    }

    @Override
    @SuppressWarnings({"unchecked","rawtypes"})
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        // 獲得代理類物件
        T proxy = proxyFactory.getProxy(invoker);
        // 如果不是返回服務呼叫
        if (GenericService.class != invoker.getInterface()) {
            // 獲得stub的配置
            String stub = invoker.getUrl().getParameter(Constants.STUB_KEY,invoker.getUrl().getParameter(Constants.LOCAL_KEY));
            // 如果配置不為空
            if (ConfigUtils.isNotEmpty(stub)) {
                Class<?> serviceType = invoker.getInterface();
                if (ConfigUtils.isDefault(stub)) {
                    // 根據local和stub來生成stub
                    if (invoker.getUrl().hasParameter(Constants.STUB_KEY)) {
                        stub = serviceType.getName() + "Stub";
                    } else {
                        stub = serviceType.getName() + "Local";
                    }
                }
                try {
                    // 生成stub類
                    Class<?> stubClass = ReflectUtils.forName(stub);
                    if (!serviceType.isAssignableFrom(stubClass)) {
                        throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName());
                    }
                    try {
                        // 獲得構造方法,該構造方法必須是帶有代理的物件的引數
                        Constructor<?> constructor = ReflectUtils.findConstructor(stubClass,serviceType);
                        // 使用指定的初始化引數建立和初始化建構函式宣告類的新例項
                        proxy = (T) constructor.newInstance(new Object[]{proxy});
                        //export stub service
                        URL url = invoker.getUrl();
                        if (url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT)) {
                            url = url.addParameter(Constants.STUB_EVENT_METHODS_KEY,StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(),","));
                            url = url.addParameter(Constants.IS_SERVER_KEY,Boolean.FALSE.toString());
                            try {
                                //  暴露stub服務
                                export(proxy,(Class) invoker.getInterface(),url);
                            } catch (Exception e) {
                                LOGGER.error("export a stub service error.",e);
                            }
                        }
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class " + stubClass.getName(),e);
                    }
                } catch (Throwable t) {
                    LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ",cause: " + t.getMessage(),t);
                    // ignore
                }
            }
        }
        return proxy;
    }

    @Override
    public <T> Invoker<T> getInvoker(T proxy,Class<T> type,URL url) throws RpcException {
        return proxyFactory.getInvoker(proxy,type,url);
    }

    private <T> Exporter<T> export(T instance,URL url) {
        return protocol.export(proxyFactory.getInvoker(instance,url));
    }
複製程式碼

該類裡面最重要的就是getProxy方法的實現,在該方法中先根據配置生成載入stub服務類,然後通過構造方法將代理的物件進行包裝,最後暴露該服務,然後返回代理類物件。

(五)JdkProxyFactory

該類繼承了AbstractProxyFactory,是jdk的代理工廠的主要邏輯。

public class JdkProxyFactory extends AbstractProxyFactory {

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker,Class<?>[] interfaces) {
        // 呼叫了 Proxy.newProxyInstance直接獲得代理類
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new InvokerInvocationHandler(invoker));
    }

    @Override
    public <T> Invoker<T> getInvoker(T proxy,URL url) {
        // 建立AbstractProxyInvoker物件
        return new AbstractProxyInvoker<T>(proxy,url) {
            @Override
            protected Object doInvoke(T proxy,Object[] arguments) throws Throwable {
                // 反射獲得方法
                Method method = proxy.getClass().getMethod(methodName,parameterTypes);
                // 執行方法
                return method.invoke(proxy,arguments);
            }
        };
    }

}
複製程式碼

不過邏輯實現比較簡單,因為jdk中都封裝好了,直接呼叫Proxy.newProxyInstance方法就可以獲得代理類。

(六)JavassistProxyFactory

該類是基於Javassist實現的動態代理工廠類。

public class JavassistProxyFactory extends AbstractProxyFactory {

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

    @Override
    public <T> Invoker<T> getInvoker(T proxy,URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        // 建立Wrapper物件
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy,Object[] arguments) throws Throwable {
                // 呼叫方法
                return wrapper.invokeMethod(proxy,methodName,parameterTypes,arguments);
            }
        };
    }

}
複製程式碼

在這裡看不出什麼具體的實現,感覺看起來跟JdkProxyFactory差不多,下面我將講解com.alibaba.dubbo.common.bytecode.Proxy類的getProxy方法和com.alibaba.dubbo.common.bytecode.Wrapper類的getWrapper方法。

(七)Proxy#getProxy()

public static Proxy getProxy(Class<?>... ics) {
    // 獲得代理類
    return getProxy(ClassHelper.getClassLoader(Proxy.class),ics);
}

/**
 * Get proxy.
 *
 * @param cl  class loader.
 * @param ics interface class array.
 * @return Proxy instance.
 */
public static Proxy getProxy(ClassLoader cl,Class<?>... ics) {
    // 最大的代理介面數限制是65535
    if (ics.length > 65535)
        throw new IllegalArgumentException("interface limit exceeded");

    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 {
            // 獲得與itf對應的Class物件
            tmp = Class.forName(itf,false,cl);
        } catch (ClassNotFoundException e) {
        }

        // 如果通過類名獲得的型別跟ics中的型別不一樣,則丟擲異常
        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 = null;
    synchronized (cache) {
        do {
            Object value = cache.get(key);
            // 如果快取中存在,則直接返回代理物件
            if (value instanceof Reference<?>) {
                proxy = (Proxy) ((Reference<?>) value).get();
                if (proxy != null)
                    return proxy;
            }

            // 是等待生成的型別,則等待
            if (value == PendingGenerationMarker) {
                try {
                    cache.wait();
                } catch (InterruptedException e) {
                }
            } else {
                // 否則放入快取中
                cache.put(key,PendingGenerationMarker);
                break;
            }
        }
        while (true);
    }
    // AtomicLong自增生成代理類類名字尾id,防止衝突
    long id = PROXY_CLASS_COUNTER.getAndIncrement();
    String pkg = null;
    ClassGenerator ccp = null,ccm = null;
    try {
        ccp = ClassGenerator.newInstance(cl);

        Set<String> worked = new HashSet<String>();
        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))
                        throw new IllegalArgumentException("non-public interfaces from different packages");
                }
            }
            // 把介面加入到ccp的mInterfaces中
            ccp.addInterface(ics[i]);

            // 遍歷每個類的方法
            for (Method method : ics[i].getMethods()) {
                // 獲得方法描述 這個方法描述是自定義:
                // 例如:int do(int arg1) => "do(I)I"
                // 例如:void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
                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();

                // 新建一句程式碼
                // 例如Object[] args = new Object[引數數量】
                StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
                // 每一個引數都生成一句程式碼
                // 例如args[0] = ($w)$1;
                // 例如 Object ret = handler.invoke(this,methods[3],args);
                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);");
                // 如果方法不是void型別
                // 則拼接 return ret;
                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;

        // create ProxyInstance class.
        String pcn = pkg + ".proxy" + id;
        ccp.setClassName(pcn);
        // 新增靜態欄位Method[] methods
        ccp.addField("public static java.lang.reflect.Method[] methods;");
        ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
        // 新增例項物件InvokerInvocationHandler hanler,新增引數為InvokerInvocationHandler的構造器
        ccp.addConstructor(Modifier.PUBLIC,new Class<?>[]{InvocationHandler.class},new Class<?>[0],"handler=$1;");
        // 新增預設無參構造器
        ccp.addDefaultConstructor();
        // 使用toClass方法生成對應的位元組碼
        Class<?> clazz = ccp.toClass();
        clazz.getField("methods").set(null,methods.toArray(new Method[0]));

        // create Proxy class.
        // 生成的位元組碼物件為服務介面的代理物件
        String fcn = Proxy.class.getName() + id;
        ccm = ClassGenerator.newInstance(cl);
        ccm.setClassName(fcn);
        ccm.addDefaultConstructor();
        ccm.setSuperClass(Proxy.class);
        ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
        Class<?> pc = ccm.toClass();
        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();
        synchronized (cache) {
            if (proxy == null)
                cache.remove(key);
            else
                cache.put(key,new WeakReference<Proxy>(proxy));
            cache.notifyAll();
        }
    }
    return proxy;
}
複製程式碼

Proxy是是生成代理物件的工具類,跟JdkProxyFactory中用到的Proxy不是同一個,JdkProxyFactory中的是jdk自帶的java.lang.reflect.Proxy。而該Proxy是dubbo基於javassit實現的com.alibaba.dubbo.common.bytecode.Proxy。該方法比較長,可以分開五個步驟來看:

  1. 遍歷代理介面,獲取介面的全限定名,並以分號分隔連線成字串,以此字串為key,查詢快取map,如果快取存在,則獲取代理物件直接返回。
  2. 由一個AtomicLong自增生成代理類類名字尾id,防止衝突
  3. 遍歷介面中的方法,獲取返回型別和引數型別,構建的方法體見註釋
  4. 建立工具類ClassGenerator例項,新增靜態欄位Method[] methods,新增例項物件InvokerInvocationHandler hanler,新增引數為InvokerInvocationHandler的構造器,新增無參構造器,然後使用toClass方法生成對應的位元組碼。
  5. 4中生成的位元組碼物件為服務介面的代理物件,而Proxy類本身是抽象類,需要實現newInstance(InvocationHandler handler)方法,生成Proxy的實現類,其中proxy0即上面生成的服務介面的代理物件。

(八)Wrapper#getWrapper

public static Wrapper getWrapper(Class<?> c) {
    // 判斷c是否繼承 ClassGenerator.DC.class ,如果是,則拿到父類,避免重複包裝
    while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
        c = c.getSuperclass();

    // 如果類為object型別
    if (c == Object.class)
        return OBJECT_WRAPPER;

    // 如果快取裡面沒有該物件,則新建一個wrapper
    Wrapper ret = WRAPPER_MAP.get(c);
    if (ret == null) {
        ret = makeWrapper(c);
        WRAPPER_MAP.put(c,ret);
    }
    return ret;
}

private static Wrapper makeWrapper(Class<?> c) {
    // 如果c不是似有類,則丟擲異常
    if (c.isPrimitive())
        throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

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

    // 設定屬性的方法第一行public void setPropertyValue(Object o,String n,Object v){
    StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o,Object v){ ");
    // 獲得屬性的方法第一行 public Object getPropertyValue(Object o,String n){
    StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o,String n){ ");
    // 執行方法的第一行
    StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o,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); }");

    Map<String,Class<?>> pts = new HashMap<String,Class<?>>(); // <property name,property types>
    Map<String,Method> ms = new LinkedHashMap<String,Method>(); // <method desc,Method instance>
    List<String> mns = new ArrayList<String>(); // method names.
    List<String> dmns = new ArrayList<String>(); // declaring method names.

    // get all public field.
    // 遍歷每個public的屬性,放入setPropertyValue和getPropertyValue方法中
    for (Field f : c.getFields()) {
        String fn = f.getName();
        Class<?> ft = f.getType();
        // // 排除有static 和 transient修飾的屬性
        if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
            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.put(fn,ft);
    }

    Method[] methods = c.getMethods();
    // get all public method.
    boolean hasMethod = hasMethods(methods);
    // 在invokeMethod方法中新增try的程式碼
    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(" ) { ");

        // 如果返回型別是void,則return null,如果不是,則返回對應引數型別
        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.add(mn);
        if (m.getDeclaringClass() == c)
            dmns.add(mn);
        ms.put(ReflectUtils.getDesc(m),m);
    }
    if (hasMethod) {
        c3.append(" } catch(Throwable e) { ");
        c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
        c3.append(" }");
    }

    c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");

    // 處理get set方法
    // deal with get/set method.
    Matcher matcher;
    for (Map.Entry<String,Method> entry : ms.entrySet()) {
        String md = entry.getKey();
        Method 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.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.put(pn,method.getReturnType());
        } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            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.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 cc = ClassGenerator.newInstance(cl);
    cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
    cc.setSuperClass(Wrapper.class);

    // 增加無參構造器
    cc.addDefaultConstructor();
    // 新增屬性
    cc.addField("public static String[] pns;"); // property name array.
    cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
    cc.addField("public static String[] mns;"); // all method name array.
    cc.addField("public static String[] dmns;"); // declared method name array.
    for (int i = 0,len = ms.size(); i < len; i++)
        cc.addField("public static Class[] mts" + i + ";");

    // 新增屬性相關的方法
    cc.addMethod("public String[] getPropertyNames(){ return pns; }");
    cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
    cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
    cc.addMethod("public String[] getMethodNames(){ return mns; }");
    cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
    cc.addMethod(c1.toString());
    cc.addMethod(c2.toString());
    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();
    }
}
複製程式碼

Wrapper是用於建立某個物件的方法呼叫的包裝器,利用位元組碼技術在呼叫方法時進行編譯相關方法。其中getWrapper就是獲得Wrapper 物件,其中關鍵的是makeWrapper方法,所以我在上面加上了makeWrapper方法的解釋,其中就是相關方法的位元組碼生成過程。

後記

該部分相關的原始碼解析地址:github.com/CrazyHZM/in…

該文章講解了遠端呼叫中關於代理的部分,關鍵部分在於基於javassist實現的位元組碼技術來支撐動態代理。接下來我將開始對rpc模組的dubbo-rpc-dubbo關於dubbo協議部分進行講解。