摘要:前言基于表單的遠程調用協議,采用的實現,關于協議就不用多說了吧。后記該部分相關的源碼解析地址該文章講解了遠程調用中關于協議的部分,內容比較簡單,可以參考著官方文檔了解一下。
遠程調用——http協議
目標:介紹遠程調用中跟http協議相關的設計和實現,介紹dubbo-rpc-http的源碼。前言
基于HTTP表單的遠程調用協議,采用 Spring 的HttpInvoker實現,關于http協議就不用多說了吧。
源碼分析 (一)HttpRemoteInvocation該類繼承了RemoteInvocation類,是在RemoteInvocation上增加了泛化調用的參數設置,以及增加了dubbo本身需要的附加值設置。
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); // 把附加值加入到會話域的屬性里面 addAttribute(dubboAttachmentsAttrName, new HashMap(二)HttpProtocol(RpcContext.getContext().getAttachments())); } @Override public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { // 獲得上下文 RpcContext context = RpcContext.getContext(); // 獲得附加值 context.setAttachments((Map ) getAttribute(dubboAttachmentsAttrName)); // 泛化標志 String generic = (String) getAttribute(Constants.GENERIC_KEY); // 如果不為空,則設置泛化標志 if (StringUtils.isNotEmpty(generic)) { context.setAttachment(Constants.GENERIC_KEY, generic); } try { // 調用下一個調用鏈 return super.invoke(targetObject); } finally { context.setAttachments(null); } } }
該類是http實現的核心,跟我在《dubbo源碼解析(二十五)遠程調用——hessian協議》中講到的HessianProtocol實現有很多地方相似。
1.屬性/** * 默認的端口號 */ public static final int DEFAULT_PORT = 80; /** * http服務器集合 */ private final Map2.doExportserverMap = new ConcurrentHashMap (); /** * Spring HttpInvokerServiceExporter 集合 */ private final Map skeletonMap = new ConcurrentHashMap (); /** * HttpBinder對象 */ private HttpBinder httpBinder;
@Override protectedRunnable doExport(final T impl, Class type, URL url) throws RpcException { // 獲得ip地址 String addr = getAddr(url); // 獲得http服務器 HttpServer server = serverMap.get(addr); // 如果服務器為空,則重新創建服務器,并且加入到集合 if (server == null) { server = httpBinder.bind(url, new InternalHandler()); serverMap.put(addr, server); } // 獲得服務path final String path = url.getAbsolutePath(); // 加入集合 skeletonMap.put(path, createExporter(impl, type)); // 通用path final String genericPath = path + "/" + Constants.GENERIC_KEY; // 添加泛化的服務調用 skeletonMap.put(genericPath, createExporter(impl, GenericService.class)); return new Runnable() { @Override public void run() { skeletonMap.remove(path); skeletonMap.remove(genericPath); } }; }
該方法是暴露服務等邏輯,因為dubbo實現http協議采用了Spring 的HttpInvoker實現,所以調用了createExporter方法來創建創建HttpInvokerServiceExporter。
3.createExporterprivateHttpInvokerServiceExporter createExporter(T impl, Class> type) { // 創建HttpInvokerServiceExporter final HttpInvokerServiceExporter httpServiceExporter = new HttpInvokerServiceExporter(); // 設置要訪問的服務的接口 httpServiceExporter.setServiceInterface(type); // 設置服務實現 httpServiceExporter.setService(impl); try { // 在BeanFactory設置了所有提供的bean屬性,初始化bean的時候執行,可以針對某個具體的bean進行配 httpServiceExporter.afterPropertiesSet(); } catch (Exception e) { throw new RpcException(e.getMessage(), e); } return httpServiceExporter; }
該方法是創建一個spring 的HttpInvokerServiceExporter。
4.doRefer@Override @SuppressWarnings("unchecked") protectedT doRefer(final Class serviceType, final URL url) throws RpcException { // 獲得泛化配置 final String generic = url.getParameter(Constants.GENERIC_KEY); // 是否為泛化調用 final boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class); // 創建HttpInvokerProxyFactoryBean final HttpInvokerProxyFactoryBean httpProxyFactoryBean = new HttpInvokerProxyFactoryBean(); // 設置RemoteInvocation的工廠類 httpProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() { /** * 為給定的AOP方法調用創建一個新的RemoteInvocation對象。 * @param methodInvocation * @return */ @Override public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { // 新建一個HttpRemoteInvocation RemoteInvocation invocation = new HttpRemoteInvocation(methodInvocation); // 如果是泛化調用 if (isGeneric) { // 設置標志 invocation.addAttribute(Constants.GENERIC_KEY, generic); } return invocation; } }); // 獲得identity message String key = url.toIdentityString(); // 如果是泛化調用 if (isGeneric) { key = key + "/" + Constants.GENERIC_KEY; } // 設置服務url httpProxyFactoryBean.setServiceUrl(key); // 設置服務接口 httpProxyFactoryBean.setServiceInterface(serviceType); // 獲得客戶端參數 String client = url.getParameter(Constants.CLIENT_KEY); if (client == null || client.length() == 0 || "simple".equals(client)) { // 創建SimpleHttpInvokerRequestExecutor連接池 使用的是JDK HttpClient SimpleHttpInvokerRequestExecutor httpInvokerRequestExecutor = new SimpleHttpInvokerRequestExecutor() { @Override protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException { super.prepareConnection(con, contentLength); // 設置讀取超時時間 con.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); // 設置連接超時時間 con.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT)); } }; httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor); } else if ("commons".equals(client)) { // 創建 HttpComponentsHttpInvokerRequestExecutor連接池 使用的是Apache HttpClient HttpComponentsHttpInvokerRequestExecutor httpInvokerRequestExecutor = new HttpComponentsHttpInvokerRequestExecutor(); // 設置讀取超時時間 httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); // 設置連接超時時間 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對象 return (T) httpProxyFactoryBean.getObject(); }
該方法是服務引用的方法,其中根據url配置simple還是commons來選擇創建連接池的方式。其中的區別就是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)) { // 返回超時異常 return RpcException.TIMEOUT_EXCEPTION; } else if (IOException.class.isAssignableFrom(cls)) { // 返回網絡異常 return RpcException.NETWORK_EXCEPTION; } else if (ClassNotFoundException.class.isAssignableFrom(cls)) { // 返回序列化異常 return RpcException.SERIALIZATION_EXCEPTION; } } return super.getErrorCode(e); }
該方法是處理異常情況,設置錯誤碼。
6.InternalHandlerprivate class InternalHandler implements HttpHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // 獲得請求uri String uri = request.getRequestURI(); // 獲得服務暴露者HttpInvokerServiceExporter對象 HttpInvokerServiceExporter skeleton = skeletonMap.get(uri); // 如果不是post,則返回碼設置500 if (!request.getMethod().equalsIgnoreCase("POST")) { response.setStatus(500); } else { // 遠程地址放到上下文 RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); try { // 調用下一個調用 skeleton.handleRequest(request, response); } catch (Throwable e) { throw new ServletException(e); } } } }
該內部類實現了HttpHandler,做了設置遠程地址的邏輯。
后記該部分相關的源碼解析地址:https://github.com/CrazyHZM/i...
該文章講解了遠程調用中關于http協議的部分,內容比較簡單,可以參考著官方文檔了解一下。接下來我將開始對rpc模塊關于injvm本地調用部分進行講解。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73199.html
摘要:大揭秘異步化改造目標從源碼的角度分析的新特性中對于異步化的改造原理。看源碼解析四十六消費端發送請求過程講到的十四的,在以前的邏輯會直接在方法中根據配置區分同步異步單向調用。改為關于可以參考源碼解析十遠程通信層的六。 2.7大揭秘——異步化改造 目標:從源碼的角度分析2.7的新特性中對于異步化的改造原理。 前言 dubbo中提供了很多類型的協議,關于協議的系列可以查看下面的文章: du...
摘要:可以參考源碼解析二十四遠程調用協議的八。十六的該類也是用了適配器模式,該類主要的作用就是增加了心跳功能,可以參考源碼解析十遠程通信層的四。二十的可以參考源碼解析十七遠程通信的一。 2.7大揭秘——消費端發送請求過程 目標:從源碼的角度分析一個服務方法調用經歷怎么樣的磨難以后到達服務端。 前言 前一篇文章講到的是引用服務的過程,引用服務無非就是創建出一個代理。供消費者調用服務的相關方法。...
摘要:而存在的意義就是保證請求或響應對象可在線程池中被解碼,解碼完成后,就會分發到的。 2.7大揭秘——服務端處理請求過程 目標:從源碼的角度分析服務端接收到請求后的一系列操作,最終把客戶端需要的值返回。 前言 上一篇講到了消費端發送請求的過程,該篇就要將服務端處理請求的過程。也就是當服務端收到請求數據包后的一系列處理以及如何返回最終結果。我們也知道消費端在發送請求的時候已經做了編碼,所以我...
摘要:客戶端對象字節輸出流請求對象響應對象增加協議頭發送請求獲得請求后的狀態碼三該類實現了接口,是創建的工廠類。該類的實現跟類類似,但是是標準的接口調用會采用的工廠類,而是的協議調用。 遠程調用——hessian協議 目標:介紹遠程調用中跟hessian協議相關的設計和實現,介紹dubbo-rpc-hessian的源碼。 前言 本文講解多是dubbo集成的第二種協議,hessian協議,He...
摘要:遠程調用協議目標介紹遠程調用中跟協議相關的設計和實現,介紹的源碼。二該類繼承了,是協議中獨有的服務暴露者。八該類也是對的裝飾,其中增強了調用次數多功能。 遠程調用——dubbo協議 目標:介紹遠程調用中跟dubbo協議相關的設計和實現,介紹dubbo-rpc-dubbo的源碼。 前言 Dubbo 缺省協議采用單一長連接和 NIO 異步通訊,適合于小數據量大并發的服務調用,以及服務消費者...
閱讀 2288·2023-04-25 14:22
閱讀 3733·2021-11-15 18:12
閱讀 1293·2019-08-30 15:44
閱讀 3215·2019-08-29 15:37
閱讀 638·2019-08-29 13:49
閱讀 3454·2019-08-26 12:11
閱讀 866·2019-08-23 18:28
閱讀 1581·2019-08-23 14:55