Dubbo服務服務暴露之ProxyFactory Invoker

Dubbo服務暴露過程當中有涉及到調用ProxyFactory 中方法獲取Invoker對象的過程,如今咱們來深究下源碼,來看下這個過程是在作些什麼,返回的Invoker 對象是什麼,咱們來看一下代碼的切入點:java

Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

這裏proxyFactory實在ServiceConfig中定義的靜態常量,賦值後沒法修改:express

private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

proxyFactory經過ExtensionLoader拓展機制進行加載。查看ProxyFactory接口源碼以下:apache

/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;

/**
 * ProxyFactory. (API/SPI, Singleton, ThreadSafe)
 *
 * @author william.liangf
 */
@SPI("javassist")
public interface ProxyFactory {

    /**
     * create proxy.
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * create invoker.
     *
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

ProxyFactory接口有三個實現類,分別爲JavassistProxyFactory、JdkProxyFactory、StubProxyFactoryWrapper。其中JavassistProxyFactory、JdkProxyFactory做爲代理工廠,StubProxyFactoryWrapper實現了對代理工廠進行裝飾的功能。在Dubbo中經過SPI配置默認的代理工廠爲JavassistProxyFactoryapp

接下來咱們重點來看JavassistProxyFactory 代理工廠:less

繼承圖以下:jvm

JavassistProxyFactory 源碼很是簡單,只有兩個方法:(代碼調試的入參已經註釋在源碼中)ide

/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.rpc.proxy.javassist;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.bytecode.Proxy;
import com.alibaba.dubbo.common.bytecode.Wrapper;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory;
import com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker;
import com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler;

/**
 * JavaassistRpcProxyFactory
 *
 * @author william.liangf
 */
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));
    }

    /**
     *
     * @param proxy DemoServiceImpl
     * @param type interface com.alibaba.dubbo.demo.DemoService
     * @param url  injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&default.accepts=1000&default.threadpool=fixed&default.threads=100&default.timeout=5000&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&owner=uce&pid=9176&side=provider&timestamp=1527927801444
     * @param <T>
     * @return
     */
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // 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);
            }
        };
    }

}

其中getProxy是實現抽象類AbstractProxyFactory中的抽象方法。AbstractProxyFactory抽象類實現了ProxyFactory接口中getProxy方法,JdkProxyFactory也實現了抽象類AbstractProxyFactory中的getProxy抽象方法。Javassist與Jdk動態代理的共同部分被封裝在父類AbstractProxyFactory中,具體的實現類只需負責實現代理生成過程的差別化部分。ui

其中getInvoker方法是在ProxyFactory接口中定義的,用於建立Invoker。getInvoker中代碼很簡單,直接返回一個匿名類。匿名類繼承了AbstractProxyInvoker抽象類,AbstractProxyInvoker抽象類又實現了Invoker接口,即代表該匿名類實現了Invoker接口,匿名類是封裝了服務提供者的調用者。this

Invoker接口定義了一個泛型。定義的方法很簡單,只有兩個方法,以下:url

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.Node;


public interface Invoker<T> extends Node {

   //獲取服務對象接口
    Class<T> getInterface();

    //獲取封裝了服務的調用者
    Result invoke(Invocation invocation) throws RpcException;

}

抽象類AbstractProxyInvoker實現了Invoker接口,AbstractProxyInvoker定義屬性和構造方法以下:

private final T proxy;

    private final Class<T> type;

    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;
    }
  • proxy:是final類型變量,指向服務提供者
  • type:是final類型變量,服務的接口類型
  • url:是final類型變量,攜帶服務地址、端口等多種信息的自定義URL對象

AbstractProxyInvoker也實現了invoker方法。方法內部很簡單,直接經過RpcResult建立一個對象便可,建立RpcResult時的構建參數是經過方法doInvoke生成的。以下:

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方法是抽象方法,由子類實現。抽象方法定義以下:

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

在ProxyFactory接口JavassistProxyFactory實現類中,getInvoker方法內部經過匿名內部類實現了doInvoke抽象方法。

Result接口主要定義了RPC 調用的相關方法,以下:

package com.alibaba.dubbo.rpc;

import java.util.Map;

public interface Result {

    Object getValue();

    Throwable getException();

    boolean hasException();

    Object recreate() throws Throwable;

    @Deprecated
    Object getResult();

    Map<String, String> getAttachments();

    String getAttachment(String key);

    String getAttachment(String key, String defaultValue);

}

RpcResult是對Result接口的一個實現。可看做對傳入對象Object的一個包裝,部分源碼以下:

public class RpcResult implements Result, Serializable {

    private static final long serialVersionUID = -6925924956850004727L;

    private Object result;

    private Throwable exception;

    private Map<String, String> attachments = new HashMap<String, String>();

    public RpcResult() {
    }

    public RpcResult(Object result) {
        this.result = result;
    }

    public RpcResult(Throwable exception) {
        this.exception = exception;
    }

    public Object recreate() throws Throwable {
        if (exception != null) {
            throw exception;
        }
        return result;
    }
}

這就是Dubbo服務發佈的Invoker生成過程

相關文章
相關標籤/搜索