模块概念的引入,是本框架的一大优势,而跨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)的更多相关文章

  1. 远程服务调用RMI框架 演示,和底层原理解析

    远程服务调用RMI框架: 是纯java写的, 只支持java服务之间的远程调用,很简单, // 接口要继承 Remote接口 public interface IHelloService extend ...

  2. spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法

    spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法 前言 本篇接着<spring boot / cloud ...

  3. dubbo专题」dubbo其实很简单,就是一个远程服务调用的框架(1)

    一.dubbo是什么? 1)本质:一个Jar包,一个分布式框架,,一个远程服务调用的分布式框架. 既然是新手教学,肯定很多同学不明白什么是分布式和远程服务调用,为什么要分布式,为什么要远程调用.我简单 ...

  4. 远程服务调用RPC框架介绍,微服务架构介绍和RPC框架对比,dubbo、SpringClound对比

    远程服务调用RPC框架介绍,微服务架构介绍和RPC框架对比,dubbo.SpringClound对比 远程服务调用RPC框架介绍,RPC简单的来说就是像调用本地服务一样调用远程服务. 分布式RPC需要 ...

  5. 【Dubbo源码阅读系列】之远程服务调用(上)

    今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...

  6. 分布式远程服务调用(RPC)框架

    分布式远程服务调用(RPC)框架 finagle:一个支持容错,协议无关的RPC系统 热门度(没变化) 10.0 活跃度(没变化) 10.0  Watchers:581 Star:6174 Fork: ...

  7. maven聚合项目以及使用dubbo远程服务调用debug操作。

    1.maven聚合项目以及使用dubbo远程服务调用debug操作. 然后操作如下所示: 然后如下所示: 启动断点所在的包的服务.以debug的形式启动. 断点进来的效果如下所示: 接下来请继续你的表 ...

  8. RPC远程服务调用

    RPC远程服务调用: RPC 的全称是 Remote Procedure Call 是一种进程间通信方式. 它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编 ...

  9. 分布式应用开发 | SpringBoot+dubbo+zookeeper实现服务注册发现 | 远程服务调用

    前言 通过新建两个独立服务--提供者.消费者,模拟两个独立分布的应用,通过使用dubbo+zookeeper来实现远程服务调用. 目录 项目搭建 provider-server consumer-se ...

随机推荐

  1. Javascript中遍历数组方法的性能对比

    Javascript中常见的遍历数组的方法 1.for循环 for(var i = 0; i < arr.length; i++) { // do something. } 2.for循环的改进 ...

  2. java历史版本下载地址

    备忘以便查阅 http://www.oracle.com/technetwork/java/archive-139210.html

  3. 使用xUnit为.net core程序进行单元测试(上)

    一. 导读 为什么要编写自动化测试程序(Automated Tests)? 可以频繁的进行测试 可以在任何时间进行测试,也可以按计划定时进行,例如:可以在半夜进行自动测试. 肯定比人工测试要快. 可以 ...

  4. MYSQL数据库表按月备份,滚动,保留6次备份

    要求: 每月1日0点:在不影响业务的情况下,备份整月的数据,保留6次备份. 思路: 基于MYSQL事件功能,每月按时完成操作 RENAME语句具有原子性,新旧表无缝切换 RENAME语句仅修改表定义, ...

  5. 记一个http-proxy-middleware 代理访问nginx映射的接口不通过的问题(connection close)

    工作过程中遇见一个问题,使用Vue-cli 搭建了一个工程,由于跨域的问题 使用了自带的dev-server Express Server(A后台) http-proxy-middleware 去访问 ...

  6. from Require.js to Webpack(why)

    写在前面: 本文主要参考 From Require.js to Webpack - Part 1 (the reasons),原文作者将项目从 require.js 转移到了 webpack 并详细说 ...

  7. vue-cli完整地引入element-ui

    1因为该组件会依赖于jQuery,所以先安装jQuery所需依赖: 进入npm控制台,输入指令: cnpm install jquery --save-dev 然后在入口文件main.js中引入: i ...

  8. lambdas了解

    Lambdas了解 功能接口的一个极其宝贵的特性是可以使用lambdas实例化它们.以下是一些关于lambdas的例子: 以逗号分隔的输入列表,左边是指定类型的输入,右边是返回的块:          ...

  9. 2017ecjtu-summer training # 9 HDU 4544

    湫湫系列故事--消灭兔子 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tota ...

  10. 最小生成树—prim算法

    最小生成树prim算法实现 所谓生成树,就是n个点之间连成n-1条边的图形.而最小生成树,就是权值(两点间直线的值)之和的最小值. 首先,要用二维数组记录点和权值.如上图所示无向图: int map[ ...