AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

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

评论

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

云渲染为设计行业带来哪些福利?

3DCAT实时渲染

哈希索引

急需上岸的小谢

9月月更

社招前端二面常见面试题

coder2028

JavaScript 前端

Nodejs安装及环境配置

nodejs NVM 9月月更

数据治理(十二):Ranger2.1.0源码编译

Lansonli

数据治理 9月月更

学人工智能难吗?怎么用它赚到钱?

felix

人工智能 赚钱 副业赚钱 算法

当代用电行为大赏:有人心疼电费,有人靠屋顶光伏“理财”

脑极体

2022-09-09:给定一个正整数 n,返回 连续正整数满足所有数字之和为 n 的组数 。 示例 1: 输入: n = 5 输出: 2 解释: 5 = 2 + 3,共有两组连续整数([5],[2,

福大大架构师每日一题

算法 rust 福大大

【C语言深度剖析】重点详解函数的形参和实参、传值和传址

Albert Edison

开发语言 传值 C语音 9月月更 传址

redis数据类型以及它们的底层实现数据结构

想要飞的猪

Java进阶(十三)servlet监听器

No Silver Bullet

Java Servlet 9月月更

【JS】两种实现-懒加载的方式-附无限滚动案例

Sam9029

JavaScript 前端 懒加载 9月月更

Python 教程之变量(1)—— 变量、表达式、条件和函数

海拥(haiyong.site)

Python 9月月更

2022 WAIC 闭幕,融云提供分论坛元宇宙直播技术支持

融云 RongCloud

直播 元宇宙

支撑全产业AI,需要怎样的算力服务?

脑极体

Web & Electron 平台即时通讯产品的技术选型

融云 RongCloud

Web Electron 即时通讯

使用 Angular Transfer State 的一个具体例子

汪子熙

typescript 前端开发 angular Web Component 9月月更

「工作小记」后台系统代码简洁之路-详情页设计

叶一一

前端 设计模式 React Hooks 9月月更

为什么低代码和专业代码走向融合才能破解低代码困境?

牛刀专业低代码

低代码 低代码平台

全球新兴市场移动应用报告

易观分析

移动应用

【JS】防抖与节流---在定义时返回的是回调函数

Sam9029

JavaScript 前端 防抖节流 9月月更

「趣学前端」前端设计模式学习与应用

叶一一

前端 设计模式 9月月更

「工作小记」多个页面的相似操作公共化设计方案

叶一一

前端 设计思维 9月月更

Python 教程之数据分析(7)—— Jupyter Notebook 入门

海拥(haiyong.site)

Python 9月月更

库调多了,都忘了最基础的概念 《锁与线程2终结篇》

知识浅谈

线程 9月月更

Java进阶(十)tomcat中context配置

No Silver Bullet

tomcat Context 9月月更

「趣学前端」今日祝福不限量,批量导入在路上

叶一一

前端 设计思维 9月月更

C++学习------cmath头文件的源码学习02

桑榆

c++ 9月月更

Ansible如何使用lookup插件模板化外部数据

山河已无恙

ansible 9月月更

ERP是什么?

优秀

ERP

这个中秋,国潮元宇宙的A新玩法是……?

文心大模型

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