飞天发布时刻:2024年 Forrester 公有云平台Wave™评估报告解读 了解详情
写点什么

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:007675

评论

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

RaftKeeper v2.1.0版本发布,性能大幅提升!

京东零售技术

大数据 企业号2024年7月PK榜 RaftKeeper

天润融通荣膺亿欧2023WIA世界创新奖多项榜单

天润融通

Python函数:函数的定义和调用

我再BUG界嘎嘎乱杀

Python 编程 后端 函数 开发语言

Blackbox AI:你的智能编程伙伴

Yan-英杰

人工智能 编译器 大模型

虚拟现实和元宇宙技术应用的差异

3DCAT实时渲染

实时云渲染 元宇宙解决方案 VR虚拟现实

观《中国数据库前世今生》,体验 TencentDB 技术的崛起。

不惑

tencentdb MySQL 8.0 中国数据库前世今生

3CX的具体介绍

cts喜友科技

通信 通讯 云通讯

从入门到精通,SnailSVN Pro——您的专业版SVN解决方案

Rose

客户在哪儿AI的企业全历史行为数据与企业信息查询平台上的数据有何区别

客户在哪儿AI

ToB营销 ToB获客 ToB增长 ToB销售 大客户营销

时序数据库如何选型?详细指标总结!

Apache IoTDB

Python函数式编程入门窥探

我再BUG界嘎嘎乱杀

Python 编程 后端 函数 开发语言

喜报!极限科技再获国家发明专利:《一种超大规模分布式集群架构的数据处理方法》,引领大数据处理技术创新

极限实验室

大数据 数据处理 国家专利

苏州1U,2U服务器托管选择哪个机房性价比高?如何托管?

苏州服务器托管

数据中心 IDC 服务器托管

刘鸿良的励志传奇与数字经济领航

科技热闻

Native Instruments Traktor Pro 数字DJ混音器 mac软件

Rose

在矿山“土壤”种植大模型,云鼎科技向产业狂奔这一年

脑极体

AI

基于 MelosBoom ,捕获 DePIN 赛道发展红利

股市老人

⾯向现代分层存储的 Caching 技术漫谈|Data Infra 研究社第十九期(含资料发布)

Databend

PDF如何一键转PPT?办公必备的2个在线工具推荐!

彭宏豪95

人工智能 PPT 办公软件 AIGC AI生成PPT

为什么StampedLock会导致CPU100%?

王磊

Java

“人本科技,智慧生活”,ARROW箭牌持续加码数智健康卫浴领域

新消费日报

这份Excel+Python飞速搞定数据分析手册,简直可以让Excel飞起来

我再BUG界嘎嘎乱杀

Python 后端 入门 开发语言 零基础

客户在哪儿AI的ToB获客服务和AI外呼机器人的有何不同

客户在哪儿AI

ToB营销 ToB获客 ToB增长 大客户营销

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