远程服务调用(RMI)
模块概念的引入,是本框架的一大优势,而跨JVM的远程服务调用则是另一个最有价值的功能。
《本地服务调用》一文中我们讲解了跨模块间的服务调用可以是这样的:
ServiceHelper.invoke("pas","AuthService:auth",new Data("principal",principalInstance,"url","http://localhost:8080/pas/index.shtml"));
如果这个pas不是本地模块,而是远程模块,又该如何调用呢?
正如你期望的那样,还是上面这样调用,这意味着,无论这个pas模块部署在什么地方,你得代码复杂度没有变化。可怜了那些靠代码量体现工作量的程序猿们,处理了一个如此复杂的工作,还是这么简单的两行代码。
远程服务的实现方法
flying中是通过hessian来实现远程调用的,主要是因为hessian简单、功能够用。
服务提供端代码:
1、定义Hessian服务提供接口
public interface RemoteService {
RemoteValue invoke(Principal principal, String moduleId, String serviceId, RemoteValue request) throws Exception;
}
2、定义Hessian的Servlet
@WebServlet(value="/remoting")
public class HessianRemoteService extends HessianServlet implements RemoteService{
private final static Logger logger = Logger.getLogger(HessianRemoteService.class);
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)servletRequest;
long start = System.currentTimeMillis();
final String requestURI = req.getRequestURI() + (req.getQueryString() == null?"":"?" + req.getQueryString());
try {
super.service(servletRequest, servletResponse);
} finally {
logger.info("Access(" + (System.currentTimeMillis() - start) + ")\tURI:" + requestURI);
}
}
public RemoteValue invoke(Principal principal, String moduleId, String serviceId, RemoteValue remoteData) throws Exception {
long start = System.currentTimeMillis();
try {
Data req = remoteData.getValue();
LocalModule module = Application.getInstance().getModules().getLocalModule(moduleId);
ThreadContext.getContext().reset(module, serviceId, req, principal);
ThreadContext.getContext().setInvokeType(ThreadContext.InvokeType.Remote);
Data result = module.invoke(serviceId, req);
remoteData.setValue(result);
} catch (Exception e){
remoteData.setException(e);
} finally {
logger.info("RemoteInvoker(" + (System.currentTimeMillis() - start) + ")\tModuleId:" + moduleId+";ServiceId:" + serviceId);
}
return remoteData;
}
}
3、实现Hessian调用的客户端
public class HessianRemoteServiceInvoker implements RemoteServiceInvoker {
@Override
public Data invoke(Principal principal, LocalModule localModule, String remoteModuleId, String serviceId, Data request)
throws Exception {
if (localModule == null) {
localModule = ThreadContext.getContext().getModule();
}
if (localModule != null) {
Thread.currentThread().setContextClassLoader(localModule.getClassLoader());
}
String url = Application.getInstance().getModules().getRemoteModule(remoteModuleId).getPath();
RemoteService remoteService = getRemoteService(url);
Map<String, Object> nonSerializable = request.filterValues(new DataFilter(){
@Override
public boolean isValid(String key, Object value) {
return key != null && value != null && (value instanceof Serializable);
}
});
final RemoteValue res = remoteService.invoke(principal, remoteModuleId, serviceId, new RemoteValue(request));
if (res.getException() != null) {
throw (Exception) res.getException();
} else {
return res.getValue().putAll(nonSerializable);
}
}
private static Map<String,RemoteService> remoteServiceMap = new ConcurrentHashMap<String, RemoteService>();
private static Object lock = new Object();
private RemoteService getRemoteService(String url) throws Exception {
RemoteService remoteService = remoteServiceMap.get(url);
if(remoteService==null){
synchronized (lock) {
remoteService = remoteServiceMap.get(url);
if(remoteService==null){
HessianProxyFactory factory = new HessianProxyFactory(Thread.currentThread().getContextClassLoader());
HttpClientHessianConnectionFactory hessianConnectionFactory = HttpClientHessianConnectionFactory.getInstance();
//hessianConnectionFactory.addHeader("authorization", "admin");
factory.setConnectionFactory(hessianConnectionFactory);
final Data config = Application.getInstance().getConfigs("hessian");
if (config != null) {
factory.setConnectTimeout(config.getLong("connectTimeout", 10000l));
factory.setReadTimeout(config.getLong("readTimeout", 10000l));
factory.setHessian2Reply(config.getBoolean("hessian2Reply", true));
factory.setHessian2Request(config.getBoolean("hesian2Request", false));
factory.setChunkedPost(config.getBoolean("chunkedPost", true));
factory.setDebug(config.getBoolean("debug", false));
}
remoteService = (RemoteService) factory.create(RemoteService.class, url);
remoteServiceMap.put(url, remoteService);
}
}
}
return remoteService;
}
}
4、实现RemoteModule中的invoke方法:
public Data invoke(String serviceId, Data request) throws Exception {
return RemoteServiceInvokerHelper.invoke(remoteServiceInvoker, id, serviceId, request);
}
框架源码:https://github.com/hifong/flying
博客空间:http://www.cnblogs.com/hifong/
Demo应用:https://github.com/hifong/pas
技术QQ群:455852142
远程服务调用(RMI)的更多相关文章
- 远程服务调用RMI框架 演示,和底层原理解析
远程服务调用RMI框架: 是纯java写的, 只支持java服务之间的远程调用,很简单, // 接口要继承 Remote接口 public interface IHelloService extend ...
- spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法
spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法 前言 本篇接着<spring boot / cloud ...
- dubbo专题」dubbo其实很简单,就是一个远程服务调用的框架(1)
一.dubbo是什么? 1)本质:一个Jar包,一个分布式框架,,一个远程服务调用的分布式框架. 既然是新手教学,肯定很多同学不明白什么是分布式和远程服务调用,为什么要分布式,为什么要远程调用.我简单 ...
- 远程服务调用RPC框架介绍,微服务架构介绍和RPC框架对比,dubbo、SpringClound对比
远程服务调用RPC框架介绍,微服务架构介绍和RPC框架对比,dubbo.SpringClound对比 远程服务调用RPC框架介绍,RPC简单的来说就是像调用本地服务一样调用远程服务. 分布式RPC需要 ...
- 【Dubbo源码阅读系列】之远程服务调用(上)
今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...
- 分布式远程服务调用(RPC)框架
分布式远程服务调用(RPC)框架 finagle:一个支持容错,协议无关的RPC系统 热门度(没变化) 10.0 活跃度(没变化) 10.0 Watchers:581 Star:6174 Fork: ...
- maven聚合项目以及使用dubbo远程服务调用debug操作。
1.maven聚合项目以及使用dubbo远程服务调用debug操作. 然后操作如下所示: 然后如下所示: 启动断点所在的包的服务.以debug的形式启动. 断点进来的效果如下所示: 接下来请继续你的表 ...
- RPC远程服务调用
RPC远程服务调用: RPC 的全称是 Remote Procedure Call 是一种进程间通信方式. 它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编 ...
- 分布式应用开发 | SpringBoot+dubbo+zookeeper实现服务注册发现 | 远程服务调用
前言 通过新建两个独立服务--提供者.消费者,模拟两个独立分布的应用,通过使用dubbo+zookeeper来实现远程服务调用. 目录 项目搭建 provider-server consumer-se ...
随机推荐
- python 学习源码练习(2)——简单文件读取
#文件创建 #!/usr/bin/python3 'makeTextFile.py--create text file' import os ls = os.linesep #get filename ...
- python * 的区别
>>> ['Spam']*5 ['Spam', 'Spam', 'Spam', 'Spam', 'Spam'] >>> ['Spam'*5] ['SpamSpamS ...
- CSS基础知识(display和visibility、overflow、文档流)
9.显示与隐藏 u display属性: (1)none:隐藏元素,不会再占有页面的任何空间,即不会影响布局. (2)inline:默认值.将元素[显示]为内联元素 (与HTML元素本身无关 ...
- 关于java解析xml文件出现的问题
DOM解析xml文件 问题1:导入javax.xml.parsers.DocumentBuilderFactory出现问题,如图: 解决办法是:由于创建工程时有个默认的jre,重新创建工程改掉就解决了 ...
- for循环相关的一个问题
首先,我在for循环外定义了两个变量. //在4条直线方向,获取预置点两端的8个点的棋盘信息 ,r=,c=;//step代表直线,r,c分别代表加上偏移量之后的坐标 ,myCount=,hisCoun ...
- Django---->模板层(template)
模板层(template) 你可能已经注意到我们在例子视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python代码之中. 1 2 3 4 def current_datetime ...
- Go并发模式:管道与取消
关键字:Go语言,管道,取消机制,并发,sync.WaitGroup,包引用,通道,defer,select GO并发模式:管道与取消 简介 Go的并发能力可以使构建一个流数据管道变得非常容易,并且可 ...
- 洛谷 P3410 拍照
洛谷 P3410 拍照 题目描述 小B有n个下属,现小B要带着一些下属让别人拍照. 有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影.如果这一些人没带齐那么就不能拍照,小B也不会得到钱. ...
- linux下,文件的权限和数字对应关系详解
命令 chmod ABC file 其中A.B.C各为一个数字,分别表示User.Group.及Other的权限. A.B.C这三个数字如果各自转换成由"0"."1&qu ...
- [bzoj2288][POJ Challenge]生日礼物
用堆维护双向链表来贪心... 数据范围显然不容许O(nm)的傻逼dp>_<..而且dp光是状态就n*m个了..显然没法优化 大概就会想到贪心乱搞了吧...一开始想贪心地通过几段小的负数把正 ...