如何將dubbo封裝成http協(xié)議

很多小伙伴在測試的時候發(fā)現(xiàn)使用現(xiàn)成的工具無法對dubbo協(xié)議進(jìn)行調(diào)用,我們現(xiàn)在就來看一下如何通過封裝馋缅,將dubbo封裝成一個http協(xié)議扒腕,然后再使用現(xiàn)成的http測試工具即可實現(xiàn)dubbo的直接調(diào)用。
首先萤悴,我們來看dubbo是啥
Dubbo是Alibaba開源的分布式服務(wù)框架瘾腰,它最大的特點是按照分層的方式來架構(gòu),使用這種方式可以使各個層之間解耦合(或者最大限度地松耦合)覆履。從服務(wù)模型的角度來看蹋盆,Dubbo采用的是一種非常簡單的模型,要么是提供方提供服務(wù)硝全,要么是消費方消費服務(wù)栖雾,所以基于這一點可以抽象出服務(wù)提供方(Provider)和服務(wù)消費方(Consumer)兩個角色。關(guān)于注冊中心伟众、協(xié)議支持析藕、服務(wù)監(jiān)控等內(nèi)容,詳見后面描述凳厢。
總體架構(gòu)
Dubbo的總體架構(gòu)账胧,如圖所示:

Paste_Image.png

Dubbo框架設(shè)計一共劃分了10個層,而最上面的Service層是留給實際想要使用Dubbo開發(fā)分布式服務(wù)的開發(fā)者實現(xiàn)業(yè)務(wù)邏輯的接口層先紫。圖中左邊淡藍(lán)背景的為服務(wù)消費方使用的接口治泥,右邊淡綠色背景的為服務(wù)提供方使用的接口, 位于中軸線上的為雙方都用到的接口遮精。
下面居夹,結(jié)合Dubbo官方文檔,我們分別理解一下框架分層架構(gòu)中,各個層次的設(shè)計要點:

服務(wù)接口層(Service):該層是與實際業(yè)務(wù)邏輯相關(guān)的准脂,根據(jù)服務(wù)提供方和服務(wù)消費方的業(yè)務(wù)設(shè)計對應(yīng)的接口和實現(xiàn)劫扒。
配置層(Config):對外配置接口,以ServiceConfig和ReferenceConfig為中心意狠,可以直接new配置類粟关,也可以通過spring解析配置生成配置類。
服務(wù)代理層(Proxy):服務(wù)接口透明代理环戈,生成服務(wù)的客戶端Stub和服務(wù)器端Skeleton,以ServiceProxy為中心澎灸,擴展接口為ProxyFactory院塞。
服務(wù)注冊層(Registry):封裝服務(wù)地址的注冊與發(fā)現(xiàn),以服務(wù)URL為中心性昭,擴展接口為RegistryFactory拦止、Registry和RegistryService∶拥撸可能沒有服務(wù)注冊中心汹族,此時服務(wù)提供方直接暴露服務(wù)。
集群層(Cluster):封裝多個提供者的路由及負(fù)載均衡其兴,并橋接注冊中心顶瞒,以Invoker為中心,擴展接口為Cluster元旬、Directory榴徐、Router和LoadBalance。將多個服務(wù)提供方組合為一個服務(wù)提供方匀归,實現(xiàn)對服務(wù)消費方來透明坑资,只需要與一個服務(wù)提供方進(jìn)行交互。
監(jiān)控層(Monitor):RPC調(diào)用次數(shù)和調(diào)用時間監(jiān)控穆端,以Statistics為中心袱贮,擴展接口為MonitorFactory、Monitor和MonitorService体啰。
遠(yuǎn)程調(diào)用層(Protocol):封將RPC調(diào)用攒巍,以Invocation和Result為中心,擴展接口為Protocol狡赐、Invoker和Exporter窑业。Protocol是服務(wù)域,它是Invoker暴露和引用的主功能入口枕屉,它負(fù)責(zé)Invoker的生命周期管理常柄。Invoker是實體域,它是Dubbo的核心模型,其它模型都向它靠擾西潘,或轉(zhuǎn)換成它卷玉,它代表一個可執(zhí)行體,可向它發(fā)起invoke調(diào)用喷市,它有可能是一個本地的實現(xiàn)相种,也可能是一個遠(yuǎn)程的實現(xiàn),也可能一個集群實現(xiàn)品姓。
信息交換層(Exchange):封裝請求響應(yīng)模式寝并,同步轉(zhuǎn)異步,以Request和Response為中心腹备,擴展接口為Exchanger衬潦、ExchangeChannel、ExchangeClient和ExchangeServer植酥。
網(wǎng)絡(luò)傳輸層(Transport):抽象mina和netty為統(tǒng)一接口镀岛,以Message為中心,擴展接口為Channel友驮、Transporter漂羊、Client、Server和Codec卸留。
數(shù)據(jù)序列化層(Serialize):可復(fù)用的一些工具走越,擴展接口為Serialization、 ObjectInput艾猜、ObjectOutput和ThreadPool买喧。

上面的介紹看不懂?沒關(guān)系匆赃,我也是從別人的論壇抄的淤毛,它就是一個分布式的協(xié)議架構(gòu),解決企業(yè)級應(yīng)用問題算柳,學(xué)dubbo之路很漫長低淡,涉及到多種協(xié)議、網(wǎng)絡(luò)知識瞬项、zookeeper蔗蹋、spring,我們統(tǒng)統(tǒng)先不管它們囱淋,直接開始將它封裝成我們熟悉的http協(xié)議猪杭。
預(yù)警:以下的代碼不是dubbo的常規(guī)用法,是小編從dubbo的spring架構(gòu)里拆出來的函數(shù)妥衣,做做工具還可以皂吮,不要拿來學(xué)做企業(yè)級應(yīng)用戒傻,否則你會越走越遠(yuǎn)。為了工具更輕量級蜂筹,我們只好將它從spring里抽離出來(小編搞了好久才完成抽離需纳,是不是應(yīng)該給個紅包)
啥?你想學(xué)常規(guī)版本的dubbo應(yīng)用艺挪,建議你還是去網(wǎng)上看dubbo教程吧不翩,出門左拐。

我們開始正式的教程麻裳。
首先口蝠,你要有個dubbo的jar包,這一點alibaba做的很好津坑,將所有dubbo需要的類封裝成了一個jar亚皂,中國平安的maven可以下載到(當(dāng)然其他的網(wǎng)站也可以):

http://maven.pingan.work/nexus/service/local/repositories/central/content/com/alibaba/dubbo/2.0.10/dubbo-2.0.10.jar
maven依賴是(如果在spring里整合出現(xiàn)jar沖突,請使用exclusion規(guī)避):
<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,具體的配置請按照標(biāo)準(zhǔn)springmvc來封裝狞谱,或者你也可以使用sevlet:


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

 /**
  * @Description: 調(diào)用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調(diào)用,不走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>();//獲取服務(wù)跟衅,注意GenericService是一個范類型孵睬,可以替代服務(wù)端任意類
   reference.setUrl("dubbo://" + bspForm.getDubboAdress() + "/" + bspForm.getDubboUrl()); //設(shè)置dubbo服務(wù)端地址和端口號
   reference.setInterface(bspForm.getDubboUrl()); //設(shè)置dubbo服務(wù)地址
   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();//獲取服務(wù)

   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 }); //調(diào)用遠(yuǎn)程類的方法
   reference.destroy();//這里一定要用伶跷,否則dubbo會一直連接掰读,沒幾十次調(diào)用系統(tǒng)就會掛掉
   return new ResponseUtil<>(CodeEnum.SUCCESS, result); //打印結(jié)果,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("返回前端的結(jié)果為:"+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("返回前端的結(jié)果為:"+jsonString);
        return jsonString;
    }
    

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雇初,隨后出現(xiàn)的幾起案子拢肆,更是在濱河造成了極大的恐慌,老刑警劉巖靖诗,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郭怪,死亡現(xiàn)場離奇詭異,居然都是意外死亡刊橘,警方通過查閱死者的電腦和手機鄙才,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來促绵,“玉大人攒庵,你說我怎么就攤上這事嘴纺。” “怎么了叙甸?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵颖医,是天一觀的道長。 經(jīng)常有香客問我裆蒸,道長熔萧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任僚祷,我火速辦了婚禮佛致,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辙谜。我一直安慰自己俺榆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布装哆。 她就那樣靜靜地躺著罐脊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜕琴。 梳的紋絲不亂的頭發(fā)上萍桌,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音凌简,去河邊找鬼上炎。 笑死,一個胖子當(dāng)著我的面吹牛雏搂,可吹牛的內(nèi)容都是我干的藕施。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼凸郑,長吁一口氣:“原來是場噩夢啊……” “哼裳食!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起线椰,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤胞谈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后憨愉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烦绳,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年配紫,在試婚紗的時候發(fā)現(xiàn)自己被綠了径密。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡躺孝,死狀恐怖享扔,靈堂內(nèi)的尸體忽然破棺而出底桂,到底是詐尸還是另有隱情,我是刑警寧澤惧眠,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布籽懦,位于F島的核電站,受9級特大地震影響氛魁,放射性物質(zhì)發(fā)生泄漏暮顺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一秀存、第九天 我趴在偏房一處隱蔽的房頂上張望捶码。 院中可真熱鬧,春花似錦或链、人聲如沸惫恼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祈纯。三九已至,卻和暖如春叼耙,著一層夾襖步出監(jiān)牢的瞬間盆繁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工旬蟋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人革娄。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓倾贰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拦惋。 傳聞我的和親對象是個殘疾皇子匆浙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容