dubbo源碼解析(三十三)遠程調用——webservice協議

遠程調用——webservice協議

目標:介紹webservice協議的設計和實現,介紹dubbo-rpc-webservice的源碼。

前言

dubbo集成webservice協議,基於 Apache CXFfrontend-simpletransports-http 實現 ,CXF 是 Apache 開源的一個 RPC 框架,由 Xfire 和 Celtix 合併而來。關於webservice協議的優勢以及介紹可以查看官方文檔,我就不多贅述。

源碼分析

(一)WebServiceProtocol

該類繼承了AbstractProxyProtocol,是webservice協議的關鍵邏輯實現。

1.屬性

/**
 * 默認端口
 */
public static final int DEFAULT_PORT = 80;

/**
 * 服務集合
 */
private final Map<String, HttpServer> serverMap = new ConcurrentHashMap<String, HttpServer>();

/**
 * 總線,該總線使用CXF內置的擴展管理器來加載組件(而不是使用Spring總線實現)。雖然加載速度更快,但它不允許像Spring總線那樣進行大量配置和定製。
 */
private final ExtensionManagerBus bus = new ExtensionManagerBus();

/**
 * http通信工廠對象
 */
private final HTTPTransportFactory transportFactory = new HTTPTransportFactory();

/**
 * http綁定者
 */
private HttpBinder httpBinder;

2.doExport

@Override
protected <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException {
    // 獲得地址
    String addr = getAddr(url);
    // 獲得http服務
    HttpServer httpServer = serverMap.get(addr);
    // 如果服務爲空,則重新創建服務器。並且加入集合
    if (httpServer == null) {
        httpServer = httpBinder.bind(url, new WebServiceHandler());
        serverMap.put(addr, httpServer);
    }
    // 服務加載器
    final ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
    // 設置地址
    serverFactoryBean.setAddress(url.getAbsolutePath());
    // 設置服務類型
    serverFactoryBean.setServiceClass(type);
    // 設置實現類
    serverFactoryBean.setServiceBean(impl);
    // 設置總線
    serverFactoryBean.setBus(bus);
    // 設置通信工廠
    serverFactoryBean.setDestinationFactory(transportFactory);
    // 創建
    serverFactoryBean.create();
    return new Runnable() {
        @Override
        public void run() {
            if(serverFactoryBean.getServer()!= null) {
                serverFactoryBean.getServer().destroy();
            }
            if(serverFactoryBean.getBus()!=null) {
                serverFactoryBean.getBus().shutdown(true);
            }
        }
    };
}

該方法是服務暴露的邏輯實現,基於cxf一些類。

3.doRefer

@Override
@SuppressWarnings("unchecked")
protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException {
    // 創建代理工廠
    ClientProxyFactoryBean proxyFactoryBean = new ClientProxyFactoryBean();
    // 設置地址
    proxyFactoryBean.setAddress(url.setProtocol("http").toIdentityString());
    // 設置服務類型
    proxyFactoryBean.setServiceClass(serviceType);
    // 設置總線
    proxyFactoryBean.setBus(bus);
    // 創建
    T ref = (T) proxyFactoryBean.create();
    // 獲得代理
    Client proxy = ClientProxy.getClient(ref);
    // 獲得HTTPConduit 處理“http”和“https”傳輸協議。實例由顯式設置或配置的策略控制
    HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
    // 用於配置客戶端HTTP端口的屬性
    HTTPClientPolicy policy = new HTTPClientPolicy();
    // 配置連接超時時間
    policy.setConnectionTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));
    // 配置調用超時時間
    policy.setReceiveTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
    conduit.setClient(policy);
    return ref;
}

該方法是服務引用的邏輯實現。

4.WebServiceHandler

private class WebServiceHandler implements HttpHandler {

    private volatile ServletController servletController;

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        // 如果servletController爲空,則重新加載一個
        if (servletController == null) {
            HttpServlet httpServlet = DispatcherServlet.getInstance();
            if (httpServlet == null) {
                response.sendError(500, "No such DispatcherServlet instance.");
                return;
            }
            // 創建servletController
            synchronized (this) {
                if (servletController == null) {
                    servletController = new ServletController(transportFactory.getRegistry(), httpServlet.getServletConfig(), httpServlet);
                }
            }
        }
        // 設置遠程地址
        RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
        // 調用方法
        servletController.invoke(request, response);
    }

}

該內部類實現了HttpHandler接口,是WebService協議的請求的處理類。

後記

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

該文章講解了遠程調用中關於webservice協議實現的部分,到這裏關於rpc遠程調用的部分就結束了,關於遠程調用核心的幾個內容就是代理、協議,再加上不同功能增強的過濾器等,關鍵是要把api中關於接口設計方面的內容看清楚,後面各類協議因爲很多都是基於第三方的框架去實現,雖然方法邏輯有所區別,但是整體的思路和框架一定順着api設計的去實現。接下來我將開始對cluster集羣模塊進行講解。

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