写点什么

Java Remoting 远程服务(下)

  • 2012-02-02
  • 本文字数:3985 字

    阅读完需:约 13 分钟

上篇分别介绍了Java Remoting 远程服务中的RMI、EJB、Web Service 等技术,下篇继续分享其他的内容。

4. Hessian

Hessian( http://hessian.caucho.com ) 是一种轻量级的 Web Service, 采用的是二进制的 RPC 协议。

图五:Hessian 架构图 [5]

如图五所示,Hessian 可以形容是一种基于二进制协议提供 RMI 功能的组件。

接下来我们使用 Hessian 来实现本文的用例。

  1. 接口类 IAnimalService.java
复制代码
public interface IAnimalService {
public String getMonkeyName();
}
  1. 实现类 AnimalServiceImp.java
复制代码
public class AnimalServiceImp implements IAnimalService {
@Override
public String getMonkeyName() {
return "I'm Jacky";
}
}
  1. 服务端容器 Tomcat 配置 Web.xml(不需要单独编写 Servlet 代码)
复制代码
<servlet>
<servlet-name>AnimalService</servlet-name>
<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
<init-param>
<param-name>home-class</param-name>
<param-value>com.demo.AnimalServiceImp</param-value>
</init-param>
<init-param>
<param-name>home-api</param-name>
<param-value>com.demo.IAnimalService</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>AnimalService</servlet-name>
<url-pattern>/service/animalService</url-pattern>
</servlet-mapping>
</servlet>
  1. 客户端 Client.java
复制代码
final String url = "http://localhost:8080/service/animalService";
HessianProxyFactory factory = new HessianProxyFactory();
IAnimalService proxy = (IAnimalService) factory.create(IAnimalService.class, url);
System.out.println(proxy.getMonkeyName());

使用 Hessian 的利弊:

  • 优势:使用简单,速度快;跨语言,跨平台;可以用来兼容 legacy 系统的功能。
  • 劣势:安全性的支持不够强,不支持两阶段事务。

通过上面的例子我们可以看出,Hessian 使用起来非常简单简单,而且性能评测结果显示 Hessian 高于基于 XML 协议的 RPC 技术 ( http://daniel.gredler.net/2008/01/07/java-remoting-protocol-benchmarks/ )。笔者认为在局域网内 Hessian 取代 WebService 是可行的,谁愿意花时间去研究相对笨重的 Web Service 框架,而且运行相率又很一般呢。大家可能想问,Hessian 到底快在哪呢?有两点,首先 Hessian 采用的是二进制的 RPC 协议,其次 Hessian 的序列化速度也比 Java 本身序列化要快。因而选择 Hessian 作为解决方案的企业也越来越多。

5. NIO(Mina/Netty)

Java NIO 可以理解为我们常说的非阻塞 IO(异步 IO),这个概念在高并发、多线程的环境里面尤为适用。NIO 的基本原理是选择器来处理 IO 请求,将每个请求做标识,塞入处理队列;每个客户端请求进入睡眠,等待唤醒。

图六:异步 IO 工作原理 [6]

图六展示了异步 IO 的工作原理,很显然异步 IO 在高并发的情况下可以节省系统很多资源(对比阻塞 IO,异步 IO 不需要开启同等数量的服务线程)。

接下来我们使用异步 IO 来实现本文的用例,第三方库使用的是 Netty。

  1. 接口类 IAnimalService.java, Request.java ```

public interface IAnimalService extends Serializable {
public String getMoneyName();
}
public class Request implements Serializable {
/**
* 序列号
/
private static final long serialVersionUID = 3701941641993894303L;@SuppressWarnings(“rawtypes”)
private Class service; // 接口类
private String method; // 调用方法名称
private Object[] paras; // 调用方法参数
private String version; // 服务版本
/
*
* @return the service
/@SuppressWarnings(“rawtypes”)
public Class getService() {
return service;
}
/
*
* @param service the service to set
/
public void setService(Class service) {
this.service = service;
}
/
*
* @return the method
/
public String getMethod() {
return method;
}
/
*
* @param method the method to set
/
public void setMethod(String method) {
this.method = method;
}
/
*
* @return the paras
/
public Object[] getParas() {
return paras;
}
/
*
* @param paras the paras to set
/
public void setParas(Object[] paras) {
this.paras = paras;
}
/
*
* @return the version
/
public String getVersion() {
return version;
}
/
*
* @param version the version to set
*/
public void setVersion(String version) {
this.version = version;
}
}

复制代码
2. 实现类 AnimalServiceImp.java ```
public class AnimalServiceImp implements IAnimalService, Serializable {
/**
* 序列号
*/
private static final long serialVersionUID = -160535222600556362L;@Override
public String getMoneyName() {
return "I'am Jackey";
}
}
  1. 服务器端 Server.java ```

final int port = 9990;
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeLine = Channels.pipeline(new SimpleChannelUpstreamHandler() {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
// 监听消息到达
Request obj = (request) e.getMessage();
if (obj.getService().equals(IAnimalService.class)) {
Method targetMethod = obj.getService().getMethod(obj.getMethod(), new Class[0]);
Object result = targetMethod.invoke(new AnimalServiceImp(), obj.getParas());
e.getChannel().write(result);
}
}
});
pipeLine.addFirst(“encoder”, new ObjectEncoder()); // 对象编码器
pipeLine.addFirst(“decoder”, new ObjectDecoder()); // 对象解码器
return pipeLine;
}
});
bootstrap.bind(new InetSocketAddress(port)); // 启动服务并绑定端口

复制代码
4. 客户端代码 Client.java ```
ClientBootstrap client = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.<i>newCachedThreadPool</i>(), Executors.<i>newCachedThreadPool</i>()));
client.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeLine = Channels.<i>pipeline</i>(new SimpleChannelUpstreamHandler() {
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
// 创建连接发送请求
Request r = new Request();
r.setVersion("1.0.0"); // 设置版本
r.setService(IAnimalService.class); // 设置服务类型
r.setMethod("getMoneyName"); // 调用服务方法名称
r.setParas(null); // 参数
e.getChannel().write(r);
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception{
// 监听消息到达
System.<i>out</i>.println(e.getMessage().toString());
}
});
pipeLine.addFirst("encoder", new ObjectEncoder()); // 对象编码器
pipeLine.addFirst("decoder", new ObjectDecoder<u>()</u>); // 对象解码器
return pipeLine;
}
});
client.setOption("tcpNoDelay", true);
client.setOption("keepAlive", true);
ChannelFuture future = client.connect(new InetSocketAddress("127.0.0.1", 9990));
future.getChannel().getCloseFuture().awaitUninterruptibly();
client.releaseExternalResources(); // 释放外部资源

上述代码的实现稍有复杂,主要的结构是客户端将请求对象编码并发送管道,服务端将接受的字节流解码为对象,调用相应的方法并将结果返还至客户端。感兴趣的读者可以查看 Netty 官网 ( http://www.jboss.org/netty ) 来了解详情。

中国最大的互联网公司之一,淘宝,内部使用的服务框架 HSF 就采用了这种方式 (采用的第三方 NIO 库是 Mina) [7] 。笔者认为使用 NIO 这种方式来做分布式应用的优劣也是非常明显的:

  1. 优点:基于 TCP 通信,效率上高于 HTTP 的方式,非阻塞 IO 应对高并发绰绰有余。根据具体的需要制定数据传输的格式,可扩展性强。
  2. 缺点:不能跨语言,无法穿透防火墙。

结论

对企业来讲,Java Remoting 采取何种方案没有一个特定的标准。根据笔者的经验,业务特点以及数据吞吐量决定了技术的选择方向。比如第三方数据接口,重点考虑的是跨平台、跨语言、支持高并发、保证安全;而局域网内的分布式服务,重点考虑的是高性能、稳定性、可伸缩性。

引用

[5] http://safehammad.com/tag/hessian/

[6] http://onjava.com/onjava/2002/09/04/nio.html

[7] http://archive.cnblogs.com/a/1963077/

[8] http://www.salesforce.com/us/developer/docs/api/index.htm

作者

李湃,上海交通大学计算机硕士毕业,5 年互联网的行业经验,现就职于国内某互联网公司,喜欢开源技术,对于 Java 企业架构、分布式技术、高性能高可靠软件设计有极大的热情,希望能对国内社区有所贡献。博客地址: http://haperkelu2011.iteye.com/


感谢崔康对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-02-02 00:007925

评论

发布
暂无评论
发现更多内容

不管卷不卷,面试还是得问问你G1原理!

艾小仙

Java 编程 程序员

“AI赋能”大学计划落地,英特尔联合生态伙伴推进产教融合

E科讯

Elastic Job简单使用

赵镇

Elastic-job

react源码解析18事件系统

全栈潇晨

React

OpenCV-Python+Moviepy结合进行视频特效处理

老猿Python

Python 音视频 Video PPT 引航计划

容器化 | MySQL on K8s 开源开放的高可用容器编排方案

RadonDB

MySQL 容器 RadonDB KubeSphere

文件保险箱——用区块链保护文件

趣链科技

区块链 区块链应用

使用 VideoToolbox 探索低延迟视频编码 | WWDC 演讲实录

网易云信

低延时

在线HTML标签清除工具

入门小站

工具

软件复杂度

海拉鲁

读书笔记 软件工程 软件设计

极狐GitLab致力打造DevSecOps 行业标准

极狐GitLab

ci 修复措施 安全扫描器 安全测试

Redis:我是如何与客户端进行通信的

码农参上

redis Redis 协议

迷惘的六月份

卢卡多多

生活状态 6月日更

Java进阶 | 泛型机制与反射原理

晨雨听风

Java

技术干货 | macOS桌面端录屏采集实现教程

ZEGO即构

大前端 音视频 WebRTC 屏幕录制

在云原生场景下构建企业级存储方案

青云技术社区

云原生

网络抓包实战01——互联⽹:客户端请求是如何到达服务器的

青春不可负,生活不可欺

Wireshark TCP/IP tcpdump 网络抓包 tcpcopy

软件开发项目中,产品经理和程序员谁更累?

万事ONES

产品经理 研发管理 ONES 项目经理

【21-15】PowerShell条件判断

耳东@Erdong

PowerShell 6月日更

在线PS(PhotoShop),打开PSD文件,图像处理

入门小站

PhotoShop ps

做好项目管理,项目经理需要具备哪些优秀品质?

万事ONES

项目管理 研发管理 研发管理工具 ONES

GO database/sql 连接池源码分析

非晓为骁

源码分析 Go 语言 连接池 database

云小课|RDS实例连接又失败?看我祭出杀手锏!

华为云开发者联盟

数据库 关系型数据库 云数据库 RDS GaussDB(for MySQL)

有状态应用如何在Kubernetes平台上快速迁移和重建

焱融科技

云计算 Kubernetes 容器 云原生 高性能

Linux之rmdir命令

入门小站

Linux

简单好用一键恢复丢失办公文档

淋雨

EasyRecovery 文件恢复 免费恢复软件 硬盘数据恢复

一次性搞清Java中的类加载问题

华为云开发者联盟

Java

详解Java中static关键字和final关键字的功能

华为云开发者联盟

Java static关键字 final关键字 静态变量

JAVA 面向对象 (十)--接口和抽象类

加百利

Java 后端 笔记 6月日更

分布式数据库在抖音春晚活动中的应用

火山引擎开发者社区

数据库 后端

Python——默认字典 (defaultdict)

在即

6月日更

Java Remoting远程服务(下)_Java_李湃_InfoQ精选文章