dubbo原始碼解析(三十一)遠端呼叫——rmi協議
遠端呼叫——rmi協議
目標:介紹rmi協議的設計和實現,介紹dubbo-rpc-rmi的原始碼。
前言
dubbo支援rmi協議,主要基於spring封裝的org.springframework.remoting.rmi包來實現,當然最原始還是依賴 JDK 標準的java.rmi.*包,採用阻塞式短連線和 JDK 標準序列化方式。關於rmi協議的介紹可以參考dubbo官方文件。
地址:http://dubbo.apache.org/zh-cn...
原始碼分析
(一)RmiRemoteInvocation
該類繼承了RemoteInvocation,主要是在RemoteInvocation的基礎上新增dubbo自身所需的附加值,避免這些附加值沒有被傳遞,為了做一些驗證處理。
public class RmiRemoteInvocation extends RemoteInvocation { private static final long serialVersionUID = 1L; private static final String dubboAttachmentsAttrName = "dubbo.attachments"; /** * executed on consumer side */ public RmiRemoteInvocation(MethodInvocation methodInvocation) { super(methodInvocation); // 新增dubbo附加值的屬性 addAttribute(dubboAttachmentsAttrName, new HashMap<String, String>(RpcContext.getContext().getAttachments())); } /** * Need to restore context on provider side (Though context will be overridden by Invocation's attachment * when ContextFilter gets executed, we will restore the attachment when Invocation is constructed, check more * 需要在提供者端恢復上下文(儘管上下文將被Invocation的附件覆蓋 * 當ContextFilter執行時,我們將在構造Invocation時恢復附件,檢查更多 * from {@link com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler} */ @SuppressWarnings("unchecked") @Override public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { // 獲得上下文 RpcContext context = RpcContext.getContext(); // 設定引數 context.setAttachments((Map<String, String>) getAttribute(dubboAttachmentsAttrName)); try { return super.invoke(targetObject); } finally { // 清空引數 context.setAttachments(null); } } }
(二)RmiProtocol
該類繼承了AbstractProxyProtocol類,是rmi協議實現的核心,跟其他協議一樣,也實現了自己的服務暴露和服務引用方法。
1.doExport
@Override protected <T> Runnable doExport(final T impl, Class<T> type, URL url) throws RpcException { // rmi暴露者 final RmiServiceExporter rmiServiceExporter = new RmiServiceExporter(); // 設定埠 rmiServiceExporter.setRegistryPort(url.getPort()); // 設定服務名稱 rmiServiceExporter.setServiceName(url.getPath()); // 設定介面 rmiServiceExporter.setServiceInterface(type); // 設定服務實現 rmiServiceExporter.setService(impl); try { // 初始化bean的時候執行 rmiServiceExporter.afterPropertiesSet(); } catch (RemoteException e) { throw new RpcException(e.getMessage(), e); } return new Runnable() { @Override public void run() { try { // 銷燬 rmiServiceExporter.destroy(); } catch (Throwable e) { logger.warn(e.getMessage(), e); } } }; }
該方法是服務暴露的邏輯實現。
2.doRefer
@Override @SuppressWarnings("unchecked") protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException { // FactoryBean對於RMI代理,支援傳統的RMI服務和RMI呼叫者,建立RmiProxyFactoryBean物件 final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean(); // RMI needs extra parameter since it uses customized remote invocation object // 檢測版本 if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()).equals(Version.getProtocolVersion())) { // Check dubbo version on provider, this feature only support // 設定RemoteInvocationFactory以用於此訪問器 rmiProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() { @Override public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { // 自定義呼叫工廠可以向呼叫新增更多上下文資訊 return new RmiRemoteInvocation(methodInvocation); } }); } // 設定此遠端訪問者的目標服務的URL。URL必須與特定遠端處理提供程式的規則相容。 rmiProxyFactoryBean.setServiceUrl(url.toIdentityString()); // 設定要訪問的服務的介面。介面必須適合特定的服務和遠端處理策略 rmiProxyFactoryBean.setServiceInterface(serviceType); // 設定是否在找到RMI存根後快取它 rmiProxyFactoryBean.setCacheStub(true); // 設定是否在啟動時查詢RMI存根 rmiProxyFactoryBean.setLookupStubOnStartup(true); // 設定是否在連線失敗時重新整理RMI存根 rmiProxyFactoryBean.setRefreshStubOnConnectFailure(true); // // 初始化bean的時候執行 rmiProxyFactoryBean.afterPropertiesSet(); return (T) rmiProxyFactoryBean.getObject(); }
該方法是服務引用的邏輯實現。
後記
該部分相關的原始碼解析地址:https://github.com/CrazyHZM/i...
該文章講解了遠端呼叫中關於rmi協議實現的部分,邏輯比較簡單。接下來我將開始對rpc模組關於thrift協議部分進行講解。