dubbo源码解析(三十一)远程调用——rmi协议

news/2025/4/22 2:12:44

远程调用——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")@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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协议部分进行讲解。


https://dhexx.cn/news/show-2611999.html

相关文章

Spring Clould负载均衡重要组件:Ribbon中重要类的用法

Ribbon是Spring Cloud Netflix全家桶中负责负载均衡的组件&#xff0c;它是一组类库的集合。通过Ribbon&#xff0c;程序员能在不涉及到具体实现细节的基础上“透明”地用到负载均衡&#xff0c;而不必在项目里过多地编写实现负载均衡的代码。比如&#xff0c;在某个包含Eureka…

LOJ #6032 「雅礼集训 2017 Day2」水箱

题目链接 https://loj.ac/problem/6032 题解 扫描线&#xff0c;先将每个操作按照y轴排序&#xff0c;考虑水从下面淹到上面。 对于挡板被截断的情况&#xff1a;并查集合并左侧和右侧的格子。 对于要求没有水的情况&#xff1a;如果水不淹到上面&#xff0c;那么它一定会被满足…

Designated Initializer 指定初始化方法

小菜编程成长记之 《Designated Initializer》 这是小菜去公司实习的第一周&#xff0c;为了好好表现自己&#xff0c;小菜下班后都留在公司继续看书学习iOS。这一天小菜在看某个开源代码的时候发现了一个之前没有见过的宏 NS_DESIGNATED_INITIALIZER。 在经过两个个小时的百度…

软件工程---gjb438b 质量规范体系

GJB438B 软件设计说明模板 https://mp.weixin.qq.com/s?__bizMjM5Mzc2NjczMQ%3D%3D&idx3&mid2651866777&sn5c8b15ef50d1574cdb6f5823dacfab7c (1) 软件研制任务书 https://www.jianshu.com/p/dfb0b22662e4 1 范围 1.1 标识 本文档适用的软件&#xff1a; a) 软件标…

你的前半生,可曾有过下定决心做某件事的时候?

作者&#xff1a;陆小凤首发&#xff1a;微信公众号【程序员江湖】不知道你们有没有看过电视剧《我的前半生》 里面的女主在遭遇家庭变故之后终于颠覆了自己&#xff0c;最终成为了独立的女性。平淡的生活看似波澜不惊&#xff0c;实际上也在消磨着你的时间&#xff0c;磨平你的…

软件工程知识点

软件开发方法 >软件开发模型 面向对象开发 结构化开发 原型开发方法 敏捷开发 同一过程开发方法&#xff08;UP&#xff09; 敏捷方法 &#xff1a; 测试先行 小版本发布 持续集成 测试驱动 结对编程&#xff08;两个人讨论方案 &#xff0c;效率好&#xff0c;风险小…

SpringAMQP 消息容器 - SimpleMessageListenerContainer

SimpleMessageListenerContainer 即简单消息监听容器。 这个类非常的强大&#xff0c;我们可以对他进行很多的设置&#xff0c;用对于消费者的配置项&#xff0c;这个类都可以满足。它有监听单个或多个队列、自动启动、自动声明功能。 它可以设置事务特性、事务管理器、事务属…

[case46]聊聊storm trident spout的_maxTransactionActive

序 本文主要研究一下storm trident spout的_maxTransactionActive MasterBatchCoordinator storm-core-1.2.2-sources.jar!/org/apache/storm/trident/topology/MasterBatchCoordinator.java TreeMap<Long, TransactionStatus> _activeTx new TreeMap<Long, Transact…

机器学习必知概念:贝叶斯估计、最大似然估计、最大后验估计

原文(我的博客):贝叶斯估计、最大似然估计、最大后验估计三者的区别 更多机器学习深度学习资源 实例分析 即使学过机器学习的人&#xff0c;对机器学习中的 MLE(极大似然估计)、MAP(最大后验估计)以及贝叶斯估计(Bayesian) 仍有可能一知半解。对于一个基础模型&#xff0c;通常…

需求工程知识点

对数据流图进行细化 状态转换图 控制类 衔接各类 同时完成业务逻辑的处理 动词名词组成 如 身份验证 uml图分类