如何将dubbo封装成http协议

很多小伙伴在测试的时候发现使用现成的工具无法对dubbo协议进行调用,我们现在就来看一下如何通过封装,将dubbo封装成一个http协议,然后再使用现成的http测试工具即可实现dubbo的直接调用。
首先,我们来看dubbo是啥
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。关于注册中心、协议支持、服务监控等内容,详见后面描述。
总体架构
Dubbo的总体架构,如图所示:

Paste_Image.png

Dubbo框架设计一共划分了10个层,而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。
下面,结合Dubbo官方文档,我们分别理解一下框架分层架构中,各个层次的设计要点:

服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
配置层(Config):对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类。
服务代理层(Proxy):服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory。
服务注册层(Registry):封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory、Registry和RegistryService。可能没有服务注册中心,此时服务提供方直接暴露服务。
集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster、Directory、Router和LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
监控层(Monitor):RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory、Monitor和MonitorService。
远程调用层(Protocol):封将RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
信息交换层(Exchange):封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger、ExchangeChannel、ExchangeClient和ExchangeServer。
网络传输层(Transport):抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel、Transporter、Client、Server和Codec。
数据序列化层(Serialize):可复用的一些工具,扩展接口为Serialization、 ObjectInput、ObjectOutput和ThreadPool。

上面的介绍看不懂?没关系,我也是从别人的论坛抄的,它就是一个分布式的协议架构,解决企业级应用问题,学dubbo之路很漫长,涉及到多种协议、网络知识、zookeeper、spring,我们统统先不管它们,直接开始将它封装成我们熟悉的http协议。
预警:以下的代码不是dubbo的常规用法,是小编从dubbo的spring架构里拆出来的函数,做做工具还可以,不要拿来学做企业级应用,否则你会越走越远。为了工具更轻量级,我们只好将它从spring里抽离出来(小编搞了好久才完成抽离,是不是应该给个红包)
啥?你想学常规版本的dubbo应用,建议你还是去网上看dubbo教程吧,出门左拐。

我们开始正式的教程。
首先,你要有个dubbo的jar包,这一点alibaba做的很好,将所有dubbo需要的类封装成了一个jar,中国平安的maven可以下载到(当然其他的网站也可以):

http://maven.pingan.work/nexus/service/local/repositories/central/content/com/alibaba/dubbo/2.0.10/dubbo-2.0.10.jar
maven依赖是(如果在spring里整合出现jar冲突,请使用exclusion规避):
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.4.10</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
</exclusions>
</dependency>

接下来直接上代码:

首先,我们先上一个springmvc的controller来封装http,具体的配置请按照标准springmvc来封装,或者你也可以使用sevlet:


@Controller
@RequestMapping(value = "/bsp", produces = "application/json; charset=utf8")
public class CallBspController extends BaseController {

 /**
  * @Description: 调用bsp
  * @author: dingjingjing058
  * @date: 2016年7月4日
  */
 @RequestMapping(value = "/callbsp.do", method = RequestMethod.GET, produces = "text/html;charset=UTF-8")
 @ResponseBody
 public String callBsp(@ModelAttribute BspForm bspForm, HttpSession httpSession) {
  if (bspForm.getDubboUrl() == null || bspForm.getDubboAdress()== null) {
   return new ResponseUtil<>(CodeEnum.PARAFORMSTMISS).toJSONString();
  }
  CallBspServiceImpl callBspServiceImpl=new CallBspServiceImpl();
  return  callBspServiceImpl.callBsp(bspForm).toJSONString();

 }
}

http传入的form如下:



package com.pingan.testcloud.form;
/**
* ClassName:UserForm 
* @Description: bsp表单类
* @author dingjingjing058
* @date 2016年7月4日
*/
public class BspForm {

private String dubboAdress;
private String dubboUrl;
private String paraMeters;

/**
 * @return the dubboUrl
 */
public String getDubboUrl() {
 return dubboUrl;
}
/**
 * @param dubboUrl the dubboUrl to set
 */
public void setDubboUrl(String dubboUrl) {
 this.dubboUrl = dubboUrl;
}
/**
 * @return the paraMeters
 */
public String getParaMeters() {
 return paraMeters;
}
/**
 * @param paraMeters the paraMeters to set
 */
public void setParaMeters(String paraMeters) {
 this.paraMeters = paraMeters;
}
/**
 * @return the dubboAdress
 */
public String getDubboAdress() {
 return dubboAdress;
}
/**
 * @param dubboAdress the dubboAdress to set
 */
public void setDubboAdress(String dubboAdress) {
 this.dubboAdress = dubboAdress;
}
}

下面来封装dubbo,我们采用直接点对点rpc调用,不走dubbo注册中心:



package com.pingan.testcloud.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;

import com.alibaba.dubbo.rpc.service.GenericService;
import com.paic.pafa.ac.dubbo.GenericParam;
import com.paic.pafa.ac.dubbo.GenericResult;
import com.pingan.testcloud.form.BspForm;
import com.pingan.testcloud.service.CallBspService;
import com.pingan.testcloud.units.CodeEnum;
import com.pingan.testcloud.units.ResponseUtil;

public class CallBspServiceImpl implements CallBspService {

 @Override
 public ResponseUtil<?> callBsp(BspForm bspForm) {

  //try {

   ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();//获取服务,注意GenericService是一个范类型,可以替代服务端任意类
   reference.setUrl("dubbo://" + bspForm.getDubboAdress() + "/" + bspForm.getDubboUrl()); //设置dubbo服务端地址和端口号
   reference.setInterface(bspForm.getDubboUrl()); //设置dubbo服务地址
   reference.setGeneric(true);
   reference.setApplication(new ApplicationConfig("ff-test"));
   reference.setTimeout(10000);
  // reference.setRegistry(new
   // RegistryConfig("zookeeper://10.21.66.48:2181"));//如果你要走zookeep管控中心,就使用它

   GenericService genericService = reference.get();//获取服务

   GenericParam param = new GenericParam();
   param.setParams(getParams(bspForm.getParaMeters()));
   GenericResult result = (GenericResult) genericService.$invoke("anymethod",
     new String[] {"com.paic.pafa.ac.dubbo.GenericParam"}, new Object[] { param }); //调用远程类的方法
   reference.destroy();//这里一定要用,否则dubbo会一直连接,没几十次调用系统就会挂掉
   return new ResponseUtil<>(CodeEnum.SUCCESS, result); //打印结果,ResponseUtil的封装见附件
  //}

  //catch (Exception e) {
//   return new ResponseUtil<>(CodeEnum.FAILURE);
  //}

 }

 public Map<String, Object> getParams(String dubboparaMeters) {
  String[] paraMeters={};
  if(dubboparaMeters!=null)
  paraMeters = dubboparaMeters.split(",");

  Map<String, Object> params = new HashMap<String, Object>();
  Map<String, Object> esbRequest = new HashMap<String, Object>();
  Map<String, Object> header = new HashMap<String, Object>();
  Map<String, Object> content = new HashMap<String, Object>();
  esbRequest.put("content", content);
  esbRequest.put("header", header);

  String sendSerialNo = this.getSeqNo();
  esbRequest.put("sendSerialNo", sendSerialNo);
  if(paraMeters!=null)
  for (String para : paraMeters) {
   String[] paraKeyValues = para.split(":");
   esbRequest.put(paraKeyValues[0], paraKeyValues[1]);
  }

  params.put("esbRequest", esbRequest);
  params.put("timeOutMs", "30000");
  params.put("systemId", "958537");
  params.put("requestNo", sendSerialNo);
  return params;
 }

 public String getSeqNo() {
  return String.valueOf(System.currentTimeMillis() + System.nanoTime() + new Random().nextInt(2));
 }
}

ok了,dubbo就封装成http了。

附件:ResponseUtil的封装

package com.pingan.testcloud.units;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.ModelMap;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;

public class ResponseUtil<T> {

    private CodeEnum responseEnum;
    private T data;
    public   Logger logger = LoggerFactory.getLogger(this.getClass());
    
    public ResponseUtil(CodeEnum responseEnum, T data){
        this.responseEnum=responseEnum;
        this.data=data;
    }
    public ResponseUtil(CodeEnum responseEnum){
        this.responseEnum=responseEnum;
    
    }
    public ResponseUtil( T data){
        this.data=data;
    }
@Override
    public String toString() {
        ModelMap modelMap = new ModelMap();
        if (responseEnum != null)
        {
            modelMap.put("code", responseEnum.getCode());
        modelMap.put("message", responseEnum.getMessage());
        }
        if (data != null) {
            modelMap.put("data", data);
        }
        String jsonString=JSON.toJSONString(modelMap);
        logger.info("返回前端的结果为:"+jsonString);
        return jsonString;
    }

    
    /**
     * @return the responseEnum
     */
    public CodeEnum getResponseEnum() {
        return responseEnum;
    }

    /**
     * @param responseEnum the responseEnum to set
     */
    public void setResponseEnum(CodeEnum responseEnum) {
        this.responseEnum = responseEnum;
    }

    /**
     * @return the data
     */
    public T getData() {
        return data;
    }

    /**
     * @param data the data to set
     */
    public void setData(T data) {
        this.data = data;
    }

    public String toJSONString(){
        ModelMap modelMap = new ModelMap();
        if (responseEnum != null)
        {
            modelMap.put("code", responseEnum.getCode());
        modelMap.put("message", responseEnum.getMessage());
        }
        if (data != null) {
            modelMap.put("data", data);
        }
         SerializeConfig mapping = new SerializeConfig();  
         String dateFormat;
         dateFormat = "yyyy-MM-dd HH:mm:ss";  
          mapping.put(Date.class, new SimpleDateFormatSerializer(dateFormat));
        String jsonString=JSON.toJSONString(modelMap,mapping);
        logger.info("返回前端的结果为:"+jsonString);
        return jsonString;
    }
    

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • Dubbo是什么 Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式...
    Coselding阅读 17,206评论 3 196
  • 本文转自:Dubbo架构设计详解,原作者是:时延军 Dubbo是Alibaba开源的分布式服务框架,它最大的特点是...
    程序熊大阅读 3,458评论 3 45
  • 开始真正意义上的改变。打卡签到。目前116. 理想体重 96 必须达到体重106 坚持。
    alaga阅读 258评论 9 0
  • 转自知通社 联合国曾经用世界著名的盖洛普民意测验方法进行了一项调查,即调查最近300年间的300位最著名的科学家是...
    有你的我的未来阅读 2,244评论 0 0