`
wanmeilingdu
  • 浏览: 23066 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java Remoting远程服务(下)

阅读更多

上篇分别介绍了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();
    }
  2. 实现类AnimalServiceImp.java
    public class AnimalServiceImp implements IAnimalService {
        @Override
        public String getMonkeyName() {
            return "I'm Jacky";
        }
    }
  3. 服务端容器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>
  4. 客户端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";
        }
    } 
  3. 服务器端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.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这种方式来做分布式应用的优劣也是非常明显的:

  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

分享到:
评论
1 楼 dacoolbaby 2012-09-20  
socket接口理论上是可以跨语言实现的。
只是使用的复杂度有待商酌。

相关推荐

    digui.rar_java remoting

    利用rmi远程调用,实现客户端和服务器端的通讯,而不是采用socket的编程方法。

    remoting:詹金斯远程模块

    詹金斯远程处理层 Jenkins remoting 是一个可执行的 JAR,它在自动化服务器中实现通信层。 它用于主 &lt;=&gt; 代理和主 &lt;=&gt; CLI 通信。 通常,该库包含引导程序代码,用于将单独的 JVM 桥接到单个半共享空间中。 ...

    Direct Web Remoting3.0

    DWR(Direct Web Remoting)是一个web远程调用框架,利用这个框架可以让AJAX变得很简单,通过DWR可以在客户端通过JavaScript直接调用服务器的Java方法并返回值给JavaScript,整个过程就好像通过本地客户端调用一样,...

    jboss remoting

    Java领域中的分布式框架比较的多,分析一个已有的远程调用框架无论是对于打算采用已有成果还是自己做分布式框架,都是很必要的事情,JBoss Remoting是其中很好很强大的一个框架,在此来对JBoss Remoting进行深入的...

    DWR(Direct Web Remoting)框架jar包.rar

    DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站。它可以允许在浏览器里的代码使用行在WEB服务器上的JAVA函数,就像它就在浏览器...

    Hessian remoting onhttp

    采用的是二进制RPC协议,Hessian更加简单、快捷,可以远程访问java类描述信息。

    remoting.io-client:使用 Engine.IO 的简单透明的远程过程调用 (RPC)

    关于Remoting.IO允许服务远程导出方法。 服务只是简单的原型 Javascript 类,它定义了许多可以远程调用的方法。 因为Engine.IO是面向连接的,所以服务是有状态的。 这意味着会话数据可以跨服务和方法调用保持。 ...

    新版Flex4下Java与BlazeDs整合的项目(含远程调用和消息服务示例)

    RT 已经含有了blazeDs.war FlashBuilder4 Tomcat6下测试通过~ 先启动后台服务 http://localhost:8080/Flex4JavaDemo/TickCacheServlet?cmd=start http://localhost:8080/Flex4JavaDemo/message.html

    dwr.jar(Direct Web Remoting)

    java工具类,DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站。它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA方法,就...

    使用BlazeDS实现Java和Flex通信

    BlazeDS是一个基于服务器的Java 远程控制(remoting)和Web消息传递(messaging)技术,它能够使得后端的Java应用程序和运行在浏览器上的Adobe Flex应用程序相互通信。这篇文章中,我讲述一种方法(也许不是最好的)使得...

    flex与java的整合教程

    使用Flex整合Java,什么...另外附加了BlazeDS的学习知识,BlazeDS是一个基于服务器的Java远程调用(remoting)和Web消息传递(messaging)技术,它能够使得后台的Java应用程序和运行在浏览器上的Flex应用程序相互通信。

    分布式实验

    分布式实验Remoting RemotingRemotingRemotingRemotingRemotingRemoting 基于java的远程调用

    腾讯java面试题合集

    腾讯的Java面试题 TCP和UDP的区别,TCP为什么是三次握手,不是两次。 答:1、因为tcp是全双工协议,区别在于前者可靠,后者不可靠,以及效率更高。  Dubbo面试题 dubbo和dubbox之间的区别? 答:Dubbox 和Dubbo本质...

    remoting:Jetlang远程处理-异步分布式消息传递

    Jetlang Remoting项目提供用于连接分布式系统的api。 Jetlang为异步分布式消息传递提供了语言不可知的线级协议和线程模型。 该库还包含客户端和服务器Websocket实现。 最新版本可在Maven存储库中获得。 #...

    DWR 最新第三版 WEB文档 AJAX

    DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA函数,就像它就在浏览器...

    DWR实现DEMO

    DWR(Direct Web Remoting)是一个web远程调用框架,利用这个框架可以让AJAX变得很简单,通过DWR可以在客户端通过JavaScript直接调用服务器的Java方法并返回值给JavaScript,整个过程就好像通过本地客户端调用一样,...

    FLex连接数据

    在本教程中,您将从数据库检索数据...本教程说明了如何创建一种数据服务,它使用 Flash Remoting 调用 PHP 类、ColdFusion 组件或 Java 类的方法。其他教程会讨论其他类型的调用,它们不在 Flex Test Drive 的范围内。

    将 Flex 集成到 Java EE 应用程序的最佳实践(完整源代码)

    有了 BlazeDS,通过简单的配置,一个 Java 接口就可以作为服务暴露给 Flex,供其远程调用。 尽管现有的 EmployeeMgmt 应用程序已经有了 Façade 接口,但这个接口是暴露给 Servlet 使用的,最好能再为 Flex 定义另...

    DWR框架包(包含所有jar、js)

    DWR(Direct Web Remoting)是一个web远程调用框架,利用这个框架可以让AJAX变得很简单,通过DWR可以在客户端通过JavaScript直接调用服务器的Java方法并返回值给JavaScript,整个过程就好像通过本地客户端调用一样,...

    .Net远程方法调用研究

    远程方法调用发展到现在,已经有以下几种框架实现:DCE/RPC,CORBA,DCOM,MTS/COM+,Java RMI,Java EJB,Web Services/SOAP/XML-RPC,NET Remoting,本文主要介绍了.NET远程方法调用的原理,实现以及与微软...

Global site tag (gtag.js) - Google Analytics