国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

dubbo源碼解析(二十六)遠(yuǎn)程調(diào)用——http協(xié)議

xiyang / 1860人閱讀

摘要:前言基于表單的遠(yuǎn)程調(diào)用協(xié)議,采用的實(shí)現(xiàn),關(guān)于協(xié)議就不用多說了吧。后記該部分相關(guān)的源碼解析地址該文章講解了遠(yuǎn)程調(diào)用中關(guān)于協(xié)議的部分,內(nèi)容比較簡單,可以參考著官方文檔了解一下。

遠(yuǎn)程調(diào)用——http協(xié)議
目標(biāo):介紹遠(yuǎn)程調(diào)用中跟http協(xié)議相關(guān)的設(shè)計(jì)和實(shí)現(xiàn),介紹dubbo-rpc-http的源碼。
前言

基于HTTP表單的遠(yuǎn)程調(diào)用協(xié)議,采用 Spring 的HttpInvoker實(shí)現(xiàn),關(guān)于http協(xié)議就不用多說了吧。

源碼分析 (一)HttpRemoteInvocation

該類繼承了RemoteInvocation類,是在RemoteInvocation上增加了泛化調(diào)用的參數(shù)設(shè)置,以及增加了dubbo本身需要的附加值設(shè)置。

public class HttpRemoteInvocation extends RemoteInvocation {

    private static final long serialVersionUID = 1L;
    /**
     * dubbo的附加值名稱
     */
    private static final String dubboAttachmentsAttrName = "dubbo.attachments";

    public HttpRemoteInvocation(MethodInvocation methodInvocation) {
        super(methodInvocation);
        // 把附加值加入到會(huì)話域的屬性里面
        addAttribute(dubboAttachmentsAttrName, new HashMap(RpcContext.getContext().getAttachments()));
    }

    @Override
    public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        // 獲得上下文
        RpcContext context = RpcContext.getContext();
        // 獲得附加值
        context.setAttachments((Map) getAttribute(dubboAttachmentsAttrName));

        // 泛化標(biāo)志
        String generic = (String) getAttribute(Constants.GENERIC_KEY);
        // 如果不為空,則設(shè)置泛化標(biāo)志
        if (StringUtils.isNotEmpty(generic)) {
            context.setAttachment(Constants.GENERIC_KEY, generic);
        }
        try {
            // 調(diào)用下一個(gè)調(diào)用鏈
            return super.invoke(targetObject);
        } finally {
            context.setAttachments(null);

        }
    }
}
(二)HttpProtocol

該類是http實(shí)現(xiàn)的核心,跟我在《dubbo源碼解析(二十五)遠(yuǎn)程調(diào)用——hessian協(xié)議》中講到的HessianProtocol實(shí)現(xiàn)有很多地方相似。

1.屬性
/**
 * 默認(rèn)的端口號(hào)
 */
public static final int DEFAULT_PORT = 80;

/**
 * http服務(wù)器集合
 */
private final Map serverMap = new ConcurrentHashMap();

/**
 * Spring HttpInvokerServiceExporter 集合
 */
private final Map skeletonMap = new ConcurrentHashMap();

/**
 * HttpBinder對(duì)象
 */
private HttpBinder httpBinder;
2.doExport
@Override
protected  Runnable doExport(final T impl, Class type, URL url) throws RpcException {
    // 獲得ip地址
    String addr = getAddr(url);
    // 獲得http服務(wù)器
    HttpServer server = serverMap.get(addr);
    // 如果服務(wù)器為空,則重新創(chuàng)建服務(wù)器,并且加入到集合
    if (server == null) {
        server = httpBinder.bind(url, new InternalHandler());
        serverMap.put(addr, server);
    }

    // 獲得服務(wù)path
    final String path = url.getAbsolutePath();

    // 加入集合
    skeletonMap.put(path, createExporter(impl, type));

    // 通用path
    final String genericPath = path + "/" + Constants.GENERIC_KEY;

    // 添加泛化的服務(wù)調(diào)用
    skeletonMap.put(genericPath, createExporter(impl, GenericService.class));
    return new Runnable() {
        @Override
        public void run() {
            skeletonMap.remove(path);
            skeletonMap.remove(genericPath);
        }
    };
}

該方法是暴露服務(wù)等邏輯,因?yàn)閐ubbo實(shí)現(xiàn)http協(xié)議采用了Spring 的HttpInvoker實(shí)現(xiàn),所以調(diào)用了createExporter方法來創(chuàng)建創(chuàng)建HttpInvokerServiceExporter。

3.createExporter
private  HttpInvokerServiceExporter createExporter(T impl, Class type) {
    // 創(chuàng)建HttpInvokerServiceExporter
    final HttpInvokerServiceExporter httpServiceExporter = new HttpInvokerServiceExporter();
    // 設(shè)置要訪問的服務(wù)的接口
    httpServiceExporter.setServiceInterface(type);
    // 設(shè)置服務(wù)實(shí)現(xiàn)
    httpServiceExporter.setService(impl);
    try {
        // 在BeanFactory設(shè)置了所有提供的bean屬性,初始化bean的時(shí)候執(zhí)行,可以針對(duì)某個(gè)具體的bean進(jìn)行配
        httpServiceExporter.afterPropertiesSet();
    } catch (Exception e) {
        throw new RpcException(e.getMessage(), e);
    }
    return httpServiceExporter;
}

該方法是創(chuàng)建一個(gè)spring 的HttpInvokerServiceExporter。

4.doRefer
@Override
@SuppressWarnings("unchecked")
protected  T doRefer(final Class serviceType, final URL url) throws RpcException {
    // 獲得泛化配置
    final String generic = url.getParameter(Constants.GENERIC_KEY);
    // 是否為泛化調(diào)用
    final boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class);

    // 創(chuàng)建HttpInvokerProxyFactoryBean
    final HttpInvokerProxyFactoryBean httpProxyFactoryBean = new HttpInvokerProxyFactoryBean();
    // 設(shè)置RemoteInvocation的工廠類
    httpProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() {
        /**
         * 為給定的AOP方法調(diào)用創(chuàng)建一個(gè)新的RemoteInvocation對(duì)象。
         * @param methodInvocation
         * @return
         */
        @Override
        public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
            // 新建一個(gè)HttpRemoteInvocation
            RemoteInvocation invocation = new HttpRemoteInvocation(methodInvocation);
            // 如果是泛化調(diào)用
            if (isGeneric) {
                // 設(shè)置標(biāo)志
                invocation.addAttribute(Constants.GENERIC_KEY, generic);
            }
            return invocation;
        }
    });
    // 獲得identity message
    String key = url.toIdentityString();
    // 如果是泛化調(diào)用
    if (isGeneric) {
        key = key + "/" + Constants.GENERIC_KEY;
    }
    // 設(shè)置服務(wù)url
    httpProxyFactoryBean.setServiceUrl(key);
    // 設(shè)置服務(wù)接口
    httpProxyFactoryBean.setServiceInterface(serviceType);
    // 獲得客戶端參數(shù)
    String client = url.getParameter(Constants.CLIENT_KEY);
    if (client == null || client.length() == 0 || "simple".equals(client)) {
        // 創(chuàng)建SimpleHttpInvokerRequestExecutor連接池 使用的是JDK HttpClient
        SimpleHttpInvokerRequestExecutor httpInvokerRequestExecutor = new SimpleHttpInvokerRequestExecutor() {
            @Override
            protected void prepareConnection(HttpURLConnection con,
                                             int contentLength) throws IOException {
                super.prepareConnection(con, contentLength);
                // 設(shè)置讀取超時(shí)時(shí)間
                con.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
                // 設(shè)置連接超時(shí)時(shí)間
                con.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));
            }
        };
        httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor);
    } else if ("commons".equals(client)) {
        // 創(chuàng)建 HttpComponentsHttpInvokerRequestExecutor連接池 使用的是Apache HttpClient
        HttpComponentsHttpInvokerRequestExecutor httpInvokerRequestExecutor = new HttpComponentsHttpInvokerRequestExecutor();
        // 設(shè)置讀取超時(shí)時(shí)間
        httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
        // 設(shè)置連接超時(shí)時(shí)間
        httpInvokerRequestExecutor.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));
        httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor);
    } else {
        throw new IllegalStateException("Unsupported http protocol client " + client + ", only supported: simple, commons");
    }
    httpProxyFactoryBean.afterPropertiesSet();
    // 返回HttpInvokerProxyFactoryBean對(duì)象
    return (T) httpProxyFactoryBean.getObject();
}

該方法是服務(wù)引用的方法,其中根據(jù)url配置simple還是commons來選擇創(chuàng)建連接池的方式。其中的區(qū)別就是SimpleHttpInvokerRequestExecutor使用的是JDK HttpClient,HttpComponentsHttpInvokerRequestExecutor 使用的是Apache HttpClient。

5.getErrorCode
@Override
protected int getErrorCode(Throwable e) {
    if (e instanceof RemoteAccessException) {
        e = e.getCause();
    }
    if (e != null) {
        Class cls = e.getClass();
        if (SocketTimeoutException.class.equals(cls)) {
            // 返回超時(shí)異常
            return RpcException.TIMEOUT_EXCEPTION;
        } else if (IOException.class.isAssignableFrom(cls)) {
            // 返回網(wǎng)絡(luò)異常
            return RpcException.NETWORK_EXCEPTION;
        } else if (ClassNotFoundException.class.isAssignableFrom(cls)) {
            // 返回序列化異常
            return RpcException.SERIALIZATION_EXCEPTION;
        }
    }
    return super.getErrorCode(e);
}

該方法是處理異常情況,設(shè)置錯(cuò)誤碼。

6.InternalHandler
private class InternalHandler implements HttpHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        // 獲得請(qǐng)求uri
        String uri = request.getRequestURI();
        // 獲得服務(wù)暴露者HttpInvokerServiceExporter對(duì)象
        HttpInvokerServiceExporter skeleton = skeletonMap.get(uri);
        // 如果不是post,則返回碼設(shè)置500
        if (!request.getMethod().equalsIgnoreCase("POST")) {
            response.setStatus(500);
        } else {
            // 遠(yuǎn)程地址放到上下文
            RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
            try {
                // 調(diào)用下一個(gè)調(diào)用
                skeleton.handleRequest(request, response);
            } catch (Throwable e) {
                throw new ServletException(e);
            }
        }
    }

}

該內(nèi)部類實(shí)現(xiàn)了HttpHandler,做了設(shè)置遠(yuǎn)程地址的邏輯。

后記
該部分相關(guān)的源碼解析地址:https://github.com/CrazyHZM/i...

該文章講解了遠(yuǎn)程調(diào)用中關(guān)于http協(xié)議的部分,內(nèi)容比較簡單,可以參考著官方文檔了解一下。接下來我將開始對(duì)rpc模塊關(guān)于injvm本地調(diào)用部分進(jìn)行講解。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/73199.html

相關(guān)文章

  • dubbo源碼解析(四十八)異步化改造

    摘要:大揭秘異步化改造目標(biāo)從源碼的角度分析的新特性中對(duì)于異步化的改造原理。看源碼解析四十六消費(fèi)端發(fā)送請(qǐng)求過程講到的十四的,在以前的邏輯會(huì)直接在方法中根據(jù)配置區(qū)分同步異步單向調(diào)用。改為關(guān)于可以參考源碼解析十遠(yuǎn)程通信層的六。 2.7大揭秘——異步化改造 目標(biāo):從源碼的角度分析2.7的新特性中對(duì)于異步化的改造原理。 前言 dubbo中提供了很多類型的協(xié)議,關(guān)于協(xié)議的系列可以查看下面的文章: du...

    lijinke666 評(píng)論0 收藏0
  • dubbo源碼解析(四十六)消費(fèi)端發(fā)送請(qǐng)求過程

    摘要:可以參考源碼解析二十四遠(yuǎn)程調(diào)用協(xié)議的八。十六的該類也是用了適配器模式,該類主要的作用就是增加了心跳功能,可以參考源碼解析十遠(yuǎn)程通信層的四。二十的可以參考源碼解析十七遠(yuǎn)程通信的一。 2.7大揭秘——消費(fèi)端發(fā)送請(qǐng)求過程 目標(biāo):從源碼的角度分析一個(gè)服務(wù)方法調(diào)用經(jīng)歷怎么樣的磨難以后到達(dá)服務(wù)端。 前言 前一篇文章講到的是引用服務(wù)的過程,引用服務(wù)無非就是創(chuàng)建出一個(gè)代理。供消費(fèi)者調(diào)用服務(wù)的相關(guān)方法。...

    fish 評(píng)論0 收藏0
  • dubbo源碼解析(四十七)服務(wù)端處理請(qǐng)求過程

    摘要:而存在的意義就是保證請(qǐng)求或響應(yīng)對(duì)象可在線程池中被解碼,解碼完成后,就會(huì)分發(fā)到的。 2.7大揭秘——服務(wù)端處理請(qǐng)求過程 目標(biāo):從源碼的角度分析服務(wù)端接收到請(qǐng)求后的一系列操作,最終把客戶端需要的值返回。 前言 上一篇講到了消費(fèi)端發(fā)送請(qǐng)求的過程,該篇就要將服務(wù)端處理請(qǐng)求的過程。也就是當(dāng)服務(wù)端收到請(qǐng)求數(shù)據(jù)包后的一系列處理以及如何返回最終結(jié)果。我們也知道消費(fèi)端在發(fā)送請(qǐng)求的時(shí)候已經(jīng)做了編碼,所以我...

    yzzz 評(píng)論0 收藏0
  • dubbo源碼解析二十五)遠(yuǎn)程調(diào)用——hessian協(xié)議

    摘要:客戶端對(duì)象字節(jié)輸出流請(qǐng)求對(duì)象響應(yīng)對(duì)象增加協(xié)議頭發(fā)送請(qǐng)求獲得請(qǐng)求后的狀態(tài)碼三該類實(shí)現(xiàn)了接口,是創(chuàng)建的工廠類。該類的實(shí)現(xiàn)跟類類似,但是是標(biāo)準(zhǔn)的接口調(diào)用會(huì)采用的工廠類,而是的協(xié)議調(diào)用。 遠(yuǎn)程調(diào)用——hessian協(xié)議 目標(biāo):介紹遠(yuǎn)程調(diào)用中跟hessian協(xié)議相關(guān)的設(shè)計(jì)和實(shí)現(xiàn),介紹dubbo-rpc-hessian的源碼。 前言 本文講解多是dubbo集成的第二種協(xié)議,hessian協(xié)議,He...

    xzavier 評(píng)論0 收藏0
  • dubbo源碼解析二十四)遠(yuǎn)程調(diào)用——dubbo協(xié)議

    摘要:遠(yuǎn)程調(diào)用協(xié)議目標(biāo)介紹遠(yuǎn)程調(diào)用中跟協(xié)議相關(guān)的設(shè)計(jì)和實(shí)現(xiàn),介紹的源碼。二該類繼承了,是協(xié)議中獨(dú)有的服務(wù)暴露者。八該類也是對(duì)的裝飾,其中增強(qiáng)了調(diào)用次數(shù)多功能。 遠(yuǎn)程調(diào)用——dubbo協(xié)議 目標(biāo):介紹遠(yuǎn)程調(diào)用中跟dubbo協(xié)議相關(guān)的設(shè)計(jì)和實(shí)現(xiàn),介紹dubbo-rpc-dubbo的源碼。 前言 Dubbo 缺省協(xié)議采用單一長連接和 NIO 異步通訊,適合于小數(shù)據(jù)量大并發(fā)的服務(wù)調(diào)用,以及服務(wù)消費(fèi)者...

    rickchen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

xiyang

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<