上篇分别介绍了Java Remoting远程服务中的RMI、EJB、Web Service等技术,下篇继续分享其他的内容。
4. Hessian
Hessian(http://hessian.caucho.com)是一种轻量级的Web Service, 采用的是二进制的RPC协议。
图五:Hessian架构图[5]
如图五所示,Hessian可以形容是一种基于二进制协议提供RMI功能的组件。
接下来我们使用Hessian来实现本文的用例。
- 接口类IAnimalService.java
public interface IAnimalService {
public String getMonkeyName();
}
- 实现类AnimalServiceImp.java
public class AnimalServiceImp implements IAnimalService {
@Override
public String getMonkeyName() {
return "I'm Jacky";
}
}
- 服务端容器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>
- 客户端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。
- 接口类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;
}
}
- 实现类AnimalServiceImp.java
public class AnimalServiceImp implements IAnimalService, Serializable {
/**
* 序列号
*/
private static final long serialVersionUID = -160535222600556362L;@Override
public String getMoneyName() {
return "I'am Jackey";
}
}
- 服务器端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)); //启动服务并绑定端口
- 客户端代码Client.java
ClientBootstrap client = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
client.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeLine = Channels.pipeline(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.out.println(e.getMessage().toString());
}
});
pipeLine.addFirst("encoder", new ObjectEncoder()); //对象编码器
pipeLine.addFirst("decoder", new ObjectDecoder()); //对象解码器
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这种方式来做分布式应用的优劣也是非常明显的:
- 优点:基于TCP通信,效率上高于HTTP的方式,非阻塞IO应对高并发绰绰有余。根据具体的需要制定数据传输的格式,可扩展性强。
- 缺点:不能跨语言,无法穿透防火墙。
结论
对企业来讲,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
分享到:
相关推荐
利用rmi远程调用,实现客户端和服务器端的通讯,而不是采用socket的编程方法。
在Spring框架中,注解是实现服务暴露和远程调用(Remoting)的重要方式,它极大地简化了配置,提高了代码的可读性和可维护性。本文将深入探讨如何使用注解来实现Spring中的Remoting服务。 首先,让我们理解什么是...
Direct Web Remoting (DWR) 是一个开源的Java库,它允许Web应用程序在客户端的JavaScript和服务器端的Java之间进行直接的、异步的通信,实现了Web应用中的Ajax功能。DWR通过自动化处理JavaScript和Java之间的类型...
Java远程技术是Java编程语言中用于实现远程通信的一系列技术手段,主要用于在不同计算机或不同进程间进行方法调用。在Java中,这种远程通信被称作远程过程调用(Remote Procedure Call, RPC)。以下是Java远程技术的...
在分布式系统中,远程调用(Remoting)是必不可少的技术之一,Spring Remoting提供了多种远程调用解决方案,帮助开发者轻松实现服务间的通信。本文将深入探讨Spring Remoting的核心概念、实现方式以及实际应用。 ...
詹金斯远程处理层 Jenkins remoting 是一个可执行的 JAR,它在自动化服务器中实现通信层。 它用于主 <=> 代理和主 <=> CLI 通信。 通常,该库包含引导程序代码,用于将单独的 JVM 桥接到单个半共享空间中。 ...
在实际应用中,Hessian Remoting常用于分布式系统中的服务调用,特别是在需要高并发、低延迟的场景下,例如微服务架构。文件列表中的“Hessian”可能包含了Hessian的相关库、示例代码或者文档,可以帮助开发者更好地...
- 在启动远程服务时,同时启用 Jrebel 热部署和远程 Debug 参数,如:`java -agentpath:./lib/libjrebel64.so -Drebel.remoting_plugin=true -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=...
1. **Remoting**: 允许Flex客户端与Java服务直接交互,实现远程方法调用(RPC)。 2. **Messaging**: 支持发布/订阅消息模式,实现事件驱动的通信。 3. **LiveCycle Data Services (LCDS)**: 提供更高级的功能,如...
Java类交互的远程服务器端Ajax开源框架DWR(Direct Web Remoting)是一个强大的工具,它允许Web应用程序在浏览器和服务器之间进行动态、实时的通信,无需刷新页面即可更新内容。DWR简化了JavaScript与Java之间的通信...
尽管在现代Java企业应用中,Spring框架下的远程调用技术(如Spring Remoting)和各种微服务架构(如Spring Cloud)逐渐流行,但Java RMI因其简单和直接性,在某些场景下依然有着不可替代的作用。
此外,.NET Remoting还支持与其他平台和技术栈的无缝集成,例如可以与Java、CORBA等技术进行通信。 #### 六、性能优化与最佳实践 - **性能优化技巧**:本书提供了许多关于如何提高.NET Remoting应用性能的方法,...
文章还提及了使用.NET Remoting技术相较于传统技术(如DCOM、CORBA和Java RMI)的优越性。如DCOM在互联网环境中的效率问题,以及.NET Remoting支持的跨平台和易于配置的优势。 最后,文章通过具体示例(图1和图2)...
总结来说,Dubbo作为一个强大的远程调用框架,不仅简化了分布式系统的开发,还提供了丰富的功能来保证服务的高可用性和高性能。通过理解并熟练掌握Dubbo的原理和使用,开发者可以更好地构建和管理大规模的分布式系统...
DWR(Direct Web Remoting)是一个web远程调用框架,利用这个框架可以让AJAX变得很简单,通过DWR可以在客户端通过JavaScript直接调用服务器的Java方法并返回值给JavaScript,整个过程就好像通过本地客户端调用一样,...
Java Spring与RMI(Remote Method Invocation)的整合是企业级应用中常见的远程服务交互方式。Spring框架提供了对RMI的支持,使得开发者能够方便地在分布式环境中进行服务的调用。这个压缩包文件“Spring+RMI”很...
Jenkins 使用 Remoting 库(通常为agent.jar或remoting.jar)实现控制器与代理之间的通信,该库允许代理从控制器加载类和类加载器资源,以便从控制器发送的 Java 对象(构建步骤等)可以在代理上执行。 Jenkins ...
3. **调用服务**:一旦代理配置完成,就可以像调用本地方法一样调用远程服务了。Java的序列化机制会自动处理参数和返回值的序列化和反序列化。 HttpInvoker的优势在于其对复杂对象的支持,特别是当参数或返回值无法...