zoukankan      html  css  js  c++  java
  • [转载] 基于Dubbo的Hessian协议实现远程调用

    转载自http://shiyanjun.cn/archives/349.html

    Dubbo基于Hessian实现了自己Hessian协议,可以直接通过配置的Dubbo内置的其他协议,在服务消费方进行远程调用,也就是说,服务调用方需要使用Java语言来基于Dubbo调用提供方服务,限制了服务调用方。同时,使用Dubbo的Hessian协议实现提供方服务,而调用方可以使用标准的Hessian接口来调用,原生的Hessian协议已经支持多语言客户端调用,支持语言如下所示:

    下面,我们的思路是,先基于Dubbo封装的Hessian协议,实现提供方服务和消费方调用服务,双方必须都使用Dubbo来开发;然后,基于Dubbo封装的Hessian协议实现提供方服务,然后服务消费方使用标准的Hessian接口来进行远程调用,分别使用Java和Python语言来实现。而且,我们实现的提供方服务通过Tomcat发布到服务注册中心。
    首先,使用Java语言定义一个搜索服务的接口,代码如下所示:

    1 package org.shirdrn.platform.dubbo.service.rpc.api;
    2  
    3 public interface SolrSearchService {
    4     String search(String collection, String q, String type, int start, int rows);
    5 }

    上面接口提供了搜索远程调用功能。

    基于Dubbo的Hessian协议实现提供方服务

    提供方实现基于Dubbo封装的Hessian协议,实现接口SolrSearchService,实现代码如下所示:

    01 package org.shirdrn.platform.dubbo.service.rpc.server;
    02  
    03 import java.io.IOException;
    04 import java.util.HashMap;
    05 import java.util.Map;
    06  
    07 import org.apache.commons.logging.Log;
    08 import org.apache.commons.logging.LogFactory;
    09 import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
    10 import org.shirdrn.platform.dubbo.service.rpc.utils.QueryPostClient;
    11 import org.springframework.context.support.ClassPathXmlApplicationContext;
    12  
    13 public class SolrSearchServer implements SolrSearchService {
    14  
    15     private static final Log LOG = LogFactory.getLog(SolrSearchServer.class);
    16     private String baseUrl;
    17     private final QueryPostClient postClient;
    18     private static final Map<String, FormatHandler> handlers = new HashMap<String, FormatHandler>(0);
    19     static {
    20         handlers.put("xml"new FormatHandler() {
    21             public String format() {
    22                 return "&wt=xml";
    23             }
    24         });
    25         handlers.put("json"new FormatHandler() {
    26             public String format() {
    27                 return "&wt=json";
    28             }
    29         });
    30     }
    31  
    32     public SolrSearchServer() {
    33         super();
    34         postClient = QueryPostClient.newIndexingClient(null);
    35     }
    36  
    37     public void setBaseUrl(String baseUrl) {
    38         this.baseUrl = baseUrl;
    39     }
    40  
    41     public String search(String collection, String q, String type, int start, int rows) {
    42         StringBuffer url = new StringBuffer();
    43         url.append(baseUrl).append(collection).append("/select?").append(q);
    44         url.append("&start=").append(start).append("&rows=").append(rows);
    45         url.append(handlers.get(type.toLowerCase()).format());
    46         LOG.info("[REQ] " + url.toString());
    47         return postClient.request(url.toString());
    48     }
    49  
    50     interface FormatHandler {
    51         String format();
    52     }
    53 }

    因为考虑到后面要使用标准Hessian接口来调用,这里接口方法参数全部使用内置标准类型。然后,我们使用Dubbo的配置文件进行配置,文件search-provider.xml的内容如下所示:

    01 <?xml version="1.0" encoding="UTF-8"?>
    02  
    07  
    08     <dubbo:application name="search-provider" />
    09     <dubbo:registry
    10         address="zookeeper://slave1:2188?backup=slave3:2188,slave4:2188" />
    11     <dubbo:protocol name="hessian" port="8080" server="servlet" />
    12     <bean id="searchService"
    13         class="org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer">
    14         <property name="baseUrl" value="http://nginx-lbserver/solr-cloud/" />
    15     </bean>
    16     <dubbo:service
    17         interface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService"
    18         ref="searchService" path="http_dubbo/search" />
    19  
    20 </beans>

    因为使用Tomcat发布提供方服务,所以我们需要实现Spring的org.springframework.web.context.ContextLoader来初始化应用上下文(基于Spring的IoC容器来管理服务对象)。实现类SearchContextLoader代码如下所示:

    01 package org.shirdrn.platform.dubbo.context;
    02  
    03 import javax.servlet.ServletContextEvent;
    04 import javax.servlet.ServletContextListener;
    05  
    06 import org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer;
    07 import org.springframework.context.support.ClassPathXmlApplicationContext;
    08 import org.springframework.web.context.ContextLoader;
    09  
    10 public class SearchContextLoader extends ContextLoader implements ServletContextListener {
    11  
    12     @Override
    13     public void contextDestroyed(ServletContextEvent arg0) {
    14         // TODO Auto-generated method stub
    15  
    16     }
    17  
    18     @Override
    19     public void contextInitialized(ServletContextEvent arg0) {
    20         String config = arg0.getServletContext().getInitParameter("contextConfigLocation");
    21         ClassPathXmlApplicationContext context = newClassPathXmlApplicationContext(config);
    22         context.start();
    23     }
    24  
    25 }

    最后,配置Web应用部署描述符文件,web.xml内容如下所示:

    01 <?xml version="1.0" encoding="UTF-8"?>
    02 <web-app id="WebApp_ID" version="2.4"
    05     <display-name>http_dubbo</display-name>
    06  
    07     <listener>
    08         <listener-class>org.shirdrn.platform.dubbo.context.SearchContextLoader</listener-class>
    09     </listener>
    10     <context-param>
    11         <param-name>contextConfigLocation</param-name>
    12         <param-value>classpath:search-provider.xml</param-value>
    13     </context-param>
    14  
    15     <servlet>
    16         <servlet-name>search</servlet-name>
    17         <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
    18         <init-param>
    19             <param-name>home-class</param-name>
    20             <param-value>org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer</param-value>
    21         </init-param>
    22         <init-param>
    23             <param-name>home-api</param-name>
    24             <param-value>org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService</param-value>
    25         </init-param>
    26         <load-on-startup>1</load-on-startup>
    27     </servlet>
    28     <servlet-mapping>
    29         <servlet-name>search</servlet-name>
    30         <url-pattern>/search</url-pattern>
    31     </servlet-mapping>
    32  
    33     <welcome-file-list>
    34         <welcome-file>index.html</welcome-file>
    35         <welcome-file>index.htm</welcome-file>
    36         <welcome-file>index.jsp</welcome-file>
    37         <welcome-file>default.html</welcome-file>
    38         <welcome-file>default.htm</welcome-file>
    39         <welcome-file>default.jsp</welcome-file>
    40     </welcome-file-list>
    41 </web-app>

    启动Tomcat以后,就可以将提供方服务发布到服务注册中心,这里服务注册中心我们使用的是ZooKeeper集群,可以参考上面Dubbo配置文件search-provider.xml的配置内容。

    下面,我们通过两种方式来调用已经注册到服务注册中心的服务。

    • 基于Dubbo的Hessian协议远程调用

    服务消费方,通过Dubbo配置文件来指定注册到注册中心的服务,配置文件search-consumer.xml的内容,如下所示:

    01 <?xml version="1.0" encoding="UTF-8"?>
    02  
    07  
    08     <dubbo:application name="search-consumer" />
    09     <dubbo:registry
    10         address="zookeeper://slave1:2188?backup=slave3:2188,slave4:2188" />
    11     <dubbo:reference id="searchService"
    12         interface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService" />
    13  
    14 </beans>

    然后,使用Java实现远程调用,实现代码如下所示:

    01 package org.shirdrn.platform.dubbo.service.rpc.client;
    02  
    03 import java.util.concurrent.Callable;
    04 import java.util.concurrent.Future;
    05  
    06 import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
    07 import org.springframework.beans.BeansException;
    08 import org.springframework.context.support.AbstractXmlApplicationContext;
    09 import org.springframework.context.support.ClassPathXmlApplicationContext;
    10  
    11 import com.alibaba.dubbo.rpc.RpcContext;
    12  
    13 public class SearchConsumer {
    14  
    15     private final String collection;
    16     private AbstractXmlApplicationContext context;
    17     private SolrSearchService searchService;
    18  
    19     public SearchConsumer(String collection, Callable<AbstractXmlApplicationContext> call) {
    20         super();
    21         this.collection = collection;
    22         try {
    23             context = call.call();
    24             context.start();
    25             searchService = (SolrSearchService) context.getBean("searchService");
    26         catch (BeansException e) {
    27             e.printStackTrace();
    28         catch (Exception e) {
    29             e.printStackTrace();
    30         }
    31     }
    32  
    33     public Future<String> asyncCall(final String q, final String type, final int start,final int rows) {
    34         Future<String> future = RpcContext.getContext().asyncCall(new Callable<String>() {
    35             public String call() throws Exception {
    36                 return search(q, type, start, rows);
    37             }
    38         });
    39         return future;
    40     }
    41  
    42     public String syncCall(final String q, final String type, final int start, final introws) {
    43         return search(q, type, start, rows);
    44     }
    45  
    46     private String search(final String q, final String type, final int start, final introws) {
    47         return searchService.search(collection, q, type, start, rows);
    48     }
    49  
    50     public static void main(String[] args) throws Exception {
    51         final String collection = "tinycollection";
    52         final String beanXML = "search-consumer.xml";
    53         final String config = SearchConsumer.class.getPackage().getName().replace('.''/') + "/" + beanXML;
    54         SearchConsumer consumer = new SearchConsumer(collection, newCallable<AbstractXmlApplicationContext>() {
    55             public AbstractXmlApplicationContext call() throws Exception {
    56                 final AbstractXmlApplicationContext context = newClassPathXmlApplicationContext(config);
    57                 return context;
    58             }
    59         });
    60  
    61         String q = "q=上海&fl=*&fq=building_type:1";
    62         int start = 0;
    63         int rows = 10;
    64         String type = "xml";
    65         for (int k = 0; k < 10; k++) {
    66             for (int i = 0; i < 10; i++) {
    67                 start = 1 10 * i;
    68                 if (i % 2 == 0) {
    69                     type = "xml";
    70                 else {
    71                     type = "json";
    72                 }
    73                 String result = consumer.syncCall(q, type, start, rows);
    74                 System.out.println(result);
    75                 // Future<String> future = consumer.asyncCall(q, type, start,
    76                 // rows);
    77                 // System.out.println(future.get());
    78             }
    79         }
    80     }
    81  
    82 }

    执行该调用实现,可以远程调用提供方发布的服务。
    这种方式限制了服务调用方也必须使用Dubbo来开发调用的代码,也就是限制了编程的语言,而无论是对于内部还是外部,各个团队之间必然存在语言的多样性,如果限制了编程语言,那么开发的服务也只能在内部使用。

    • 基于标准Hessian协议接口的远程调用

    下面,使用标准Hessian接口来实现远程调用,这时就不需要关心服务提供方的所使用的开发语言,因为最终是通过HTTP的方式来访问。我们需要下载Hessian对应语言的调用实现库,才能更方便地编程。

    使用Java语言实现远程调用
    使用Java语言实现,代码如下所示:

    01 package org.shirdrn.rpc.hessian;
    02  
    03 import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService;
    04  
    05 import com.caucho.hessian.client.HessianProxyFactory;
    06  
    07 public class HessianConsumer {
    08  
    09     public static void main(String[] args) throws Throwable {
    10  
    11         String serviceUrl = "http://10.95.3.74:8080/http_dubbo/search";
    12         HessianProxyFactory factory = new HessianProxyFactory();
    13  
    14         SolrSearchService searchService = (SolrSearchService) factory.create(SolrSearchService.class, serviceUrl);
    15  
    16         String q = "q=上海&fl=*&fq=building_type:1";
    17         String collection = "tinycollection";
    18         int start = 0;
    19         int rows = 10;
    20         String type = "xml";
    21         String result = searchService.search(collection, q, type, start, rows);
    22         System.out.println(result);
    23     }
    24 }

    我们只需要知道提供服务暴露的URL和服务接口即可,这里URL为http://10.95.3.74:8080/http_dubbo/search,接口为org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService。运行上面程序,可以调用提供方发布的服务。

    使用Python语言实现远程调用
    使用Python客户端来进行远程调用,我们可以从https://github.com/bgilmore/mustaine下载,然后安装Hessian的代理客户端Python实现库:

    2 cd mustaine
    3 sudo python setup.py install

    然后就可以使用了,使用Python进行远程调用的实现代码如下所示:

    01 #!/usr/bin/python
    02  
    03 # coding=utf-8
    04 from mustaine.client import HessianProxy
    05  
    07 = 'q=*:*&fl=*&fq=building_type:1'
    08 start = 0
    09 rows = 10
    10 resType = 'xml'
    11 collection = 'tinycollection'
    12  
    13 if __name__ == '__main__':
    14      proxy = HessianProxy(serviceUrl)
    15      result = proxy.search(collection, q, resType, start, rows)
    16      print result

    运行上面程序,就可以看到远程调用的结果。

    参考链接

  • 相关阅读:
    Jenkins安装(一)
    Ansible(一) 安装与简单测试
    zabbix中文乱码
    mysql5.7免密登录
    Zabbix 监控 Nginx 模板
    zabbix通过snmp监控主机
    zabbix5.0+grafana 使用脚本安装
    Eth-trunk配置-LACP模式
    Eth-Trunk配置-手动模式
    文件系统简单理解与实操(ext4)
  • 原文地址:https://www.cnblogs.com/scott19820130/p/4614938.html
Copyright © 2011-2022 走看看