dubbo源碼解析(二十三)遠程調用——Proxy

遠程調用——Proxy

目標:介紹遠程調用代理的設計和實現,介紹dubbo-rpc-api中的各類proxy包的源碼。

前言

首先聲明叫作代理,代理在不少領域都存在,最形象的就是如今朋友圈的微商代理,廠家委託代理幫他們賣東西。這樣作廠家對於消費者來講就是透明的,而且代理能夠本身加上一些活動或者銷售措施,但這並不影響到廠家。這裏的廠家就是委託類,而代理就能夠抽象爲代理類。這樣作有兩個優勢,第一是能夠隱藏代理類的實現,第二就是委託類和調用方的解耦,而且可以在不修改委託類本來的邏輯狀況下新增一些額外的處理。html

代理分爲兩種,靜態代理和動態代理。java

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

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

dubbo-framework

咱們能看到左邊是消費者的調用鏈,只有當消費者調用的時候,ProxyFactory纔會經過Proxy把接口實現轉化爲invoker,而且在其餘層的調用都使用的是invoker,一樣的道理,在服務提供者暴露服務的時候,也只有在最後暴露給消費者的時候纔會經過Proxy 將 Invoker 轉成接口。github

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

  1. 第一種jdk,jdk動態代理比較簡單,它內置在JDK中,所以不依賴第三方jar包,可是功能相對較弱,當調用Proxy 的靜態方法建立動態代理類時,類名格式是「$ProxyN」,N表明第 N 次生成的動態代理類,若是重複建立動態代理類會直接返回原先建立的代理類。可是這個以「\$ProxyN」命名的類是繼承Proxy類的,而且實現了其所代理的一組接口,這裏就出現了它的一個侷限性,因爲java的類只能單繼承,因此JDK動態代理僅支持接口代理。
  2. 第二種是Javassist,Javassist是一款Java字節碼引擎工具,可以在運行時編譯生成class。該方法也是代理的默認方法。

源碼分析

(一)AbstractProxyFactory

該類是代理工廠的抽象類,主要處理了一下須要代理的接口,而後把代理getProxy方法抽象出來。api

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, 0, 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,另外一個則是抽象方法。該方法被子類實現。app

(三)InvokerInvocationHandler

該類實現了InvocationHandler接口,動態代理類都必需要實現InvocationHandler接口,而該類實現的是對於基礎方法不適用rpc調用,其餘方法使用rpc調用。ide

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

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

地址: http://dubbo.apache.org/zh-cn...
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, Class<T> type, URL url) {
        return protocol.export(proxyFactory.getInvoker(instance, type, 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(), interfaces, new InvokerInvocationHandler(invoker));
    }

    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // 建立AbstractProxyInvoker對象
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      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, Class<T> type, 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, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      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, String n, 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, 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); }");

    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方法的解釋,其中就是相關方法的字節碼生成過程。

後記

該部分相關的源碼解析地址: https://github.com/CrazyHZM/i...

該文章講解了遠程調用中關於代理的部分,關鍵部分在於基於javassist實現的字節碼技術來支撐動態代理。接下來我將開始對rpc模塊的dubbo-rpc-dubbo關於dubbo協議部分進行講解。

相關文章
相關標籤/搜索